2014-11-13 19:30:51 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2007 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "randrcrtc.h"
|
|
|
|
#include "randrscreen.h"
|
|
|
|
#include "randroutput.h"
|
|
|
|
#include "randrmode.h"
|
|
|
|
|
|
|
|
RandRCrtc::RandRCrtc(RandRScreen *parent, RRCrtc id)
|
2022-11-03 14:20:15 +02:00
|
|
|
: QObject(parent),
|
|
|
|
m_currentRect(0, 0, 0, 0),
|
|
|
|
m_originalRect(m_currentRect),
|
|
|
|
m_proposedRect(m_originalRect)
|
2014-11-13 19:30:51 +02:00
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
m_screen = parent;
|
|
|
|
Q_ASSERT(m_screen);
|
|
|
|
|
|
|
|
m_currentRotation = m_originalRotation = m_proposedRotation = RandR::Rotate0;
|
|
|
|
m_currentRate = m_originalRate = m_proposedRate = 0;
|
|
|
|
m_currentMode = 0;
|
|
|
|
m_rotations = RandR::Rotate0;
|
|
|
|
|
|
|
|
m_id = id;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
RandRCrtc::~RandRCrtc()
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
// do nothing for now
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
RRCrtc RandRCrtc::id() const
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return m_id;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int RandRCrtc::rotations() const
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return m_rotations;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int RandRCrtc::rotation() const
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return m_currentRotation;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::isValid(void) const
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return m_id != None;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RandRCrtc::loadSettings(bool notify)
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
if (m_id == None) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
kDebug() << "Querying information about CRTC" << m_id;
|
|
|
|
|
|
|
|
int changes = 0;
|
|
|
|
XRRCrtcInfo *info = XRRGetCrtcInfo(QX11Info::display(), m_screen->resources(), m_id);
|
|
|
|
Q_ASSERT(info);
|
|
|
|
|
|
|
|
if (RandR::timestamp != info->timestamp) {
|
|
|
|
RandR::timestamp = info->timestamp;
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect rect = QRect(info->x, info->y, info->width, info->height);
|
|
|
|
if (rect != m_currentRect) {
|
|
|
|
m_currentRect = rect;
|
|
|
|
changes |= RandR::ChangeRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get all connected outputs
|
|
|
|
// and create a list of modes that are available in all connected outputs
|
|
|
|
OutputList outputs;
|
|
|
|
|
|
|
|
for (int i = 0; i < info->noutput; ++i) {
|
|
|
|
outputs.append(info->outputs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if the list changed from the original one
|
|
|
|
if (outputs != m_connectedOutputs) {
|
|
|
|
changes |= RandR::ChangeOutputs;
|
|
|
|
m_connectedOutputs = outputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get all outputs this crtc can be connected to
|
|
|
|
outputs.clear();
|
|
|
|
for (int i = 0; i < info->npossible; ++i) {
|
|
|
|
outputs.append(info->possible[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (outputs != m_possibleOutputs) {
|
|
|
|
changes |= RandR::ChangeOutputs;
|
|
|
|
m_possibleOutputs = outputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get all rotations
|
|
|
|
m_rotations = info->rotations;
|
|
|
|
if (m_currentRotation != info->rotation) {
|
|
|
|
m_currentRotation = info->rotation;
|
|
|
|
changes |= RandR::ChangeRotation;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if the current mode has changed
|
|
|
|
if (m_currentMode != info->mode) {
|
|
|
|
m_currentMode = info->mode;
|
|
|
|
changes |= RandR::ChangeMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
RandRMode m = m_screen->mode(m_currentMode);
|
|
|
|
if (m_currentRate != m.refreshRate()) {
|
|
|
|
m_currentRate = m.refreshRate();
|
|
|
|
changes |= RandR::ChangeRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
// just to make sure it gets initialized
|
|
|
|
m_proposedRect = m_currentRect;
|
|
|
|
m_proposedRotation = m_currentRotation;
|
|
|
|
m_proposedRate = m_currentRate;
|
|
|
|
|
|
|
|
// free the info
|
|
|
|
XRRFreeCrtcInfo(info);
|
|
|
|
|
|
|
|
if (changes && notify) {
|
|
|
|
emit crtcChanged(m_id, changes);
|
|
|
|
}
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RandRCrtc::handleEvent(XRRCrtcChangeNotifyEvent *event)
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
kDebug() << "[CRTC] Event...";
|
|
|
|
int changed = 0;
|
|
|
|
|
|
|
|
if (event->mode != m_currentMode) {
|
|
|
|
kDebug() << " Changed mode";
|
|
|
|
changed |= RandR::ChangeMode;
|
|
|
|
m_currentMode = event->mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event->rotation != m_currentRotation) {
|
|
|
|
kDebug() << " Changed rotation: " << event->rotation;
|
|
|
|
changed |= RandR::ChangeRotation;
|
|
|
|
m_currentRotation = event->rotation;
|
|
|
|
}
|
|
|
|
if (event->x != m_currentRect.x() || event->y != m_currentRect.y()) {
|
|
|
|
kDebug() << " Changed position: " << event->x << "," << event->y;
|
|
|
|
changed |= RandR::ChangeRect;
|
|
|
|
m_currentRect.moveTopLeft(QPoint(event->x, event->y));
|
|
|
|
}
|
|
|
|
|
|
|
|
RandRMode mode = m_screen->mode(m_currentMode);
|
|
|
|
if (mode.size() != m_currentRect.size()) {
|
|
|
|
kDebug() << " Changed size: " << mode.size();
|
|
|
|
changed |= RandR::ChangeRect;
|
|
|
|
m_currentRect.setSize(mode.size());
|
|
|
|
//Do NOT use event->width and event->height here, as it is being returned wrongly
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed) {
|
|
|
|
emit crtcChanged(m_id, changed);
|
|
|
|
}
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
RandRMode RandRCrtc::mode() const
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return m_screen->mode(m_currentMode);
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
QRect RandRCrtc::rect() const
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return m_currentRect;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
float RandRCrtc::refreshRate() const
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return m_currentRate;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::applyProposed()
|
|
|
|
{
|
2022-11-06 12:47:21 +02:00
|
|
|
kDebug() << "Applying proposed changes for CRTC" << m_id << "...";
|
|
|
|
kDebug() << " Current Screen rect:" << m_screen->rect();
|
|
|
|
kDebug() << " Current CRTC rect:" << m_currentRect;
|
|
|
|
kDebug() << " Current rotation:" << m_currentRotation;
|
|
|
|
kDebug() << " Proposed CRTC rect:" << m_proposedRect;
|
|
|
|
kDebug() << " Proposed rotation:" << m_proposedRotation;
|
|
|
|
kDebug() << " Proposed refresh rate:" << m_proposedRate;
|
|
|
|
kDebug() << " Enabled outputs:";
|
|
|
|
if (m_connectedOutputs.isEmpty()) {
|
|
|
|
kDebug() << " - none";
|
|
|
|
}
|
|
|
|
for (int i = 0; i < m_connectedOutputs.count(); ++i) {
|
|
|
|
kDebug() << " -" << m_screen->output(m_connectedOutputs.at(i))->name();
|
|
|
|
}
|
|
|
|
|
|
|
|
RandRMode mode;
|
|
|
|
if (m_proposedRect.size() == m_currentRect.size() && m_proposedRate == m_currentRate) {
|
|
|
|
mode = m_screen->mode(m_currentMode);
|
|
|
|
} else {
|
|
|
|
// find a mode that has the desired size and is supported
|
|
|
|
// by all connected outputs
|
|
|
|
ModeList modeList = modes();
|
|
|
|
ModeList matchModes;
|
|
|
|
|
|
|
|
foreach(RRMode m, modeList)
|
|
|
|
{
|
|
|
|
RandRMode mode = m_screen->mode(m); {
|
|
|
|
if (mode.size() == m_proposedRect.size())
|
|
|
|
matchModes.append(m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no matching modes were found, disable output
|
|
|
|
// else set the mode to the first mode in the list. If no refresh rate was given
|
|
|
|
// or no mode was found matching the given refresh rate, the first mode of the
|
|
|
|
// list will be used
|
|
|
|
if (!matchModes.count()) {
|
|
|
|
mode = RandRMode();
|
|
|
|
} else {
|
|
|
|
mode = m_screen->mode(matchModes.first());
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach(RRMode m, matchModes) {
|
|
|
|
RandRMode testMode = m_screen->mode(m);
|
|
|
|
if (testMode.refreshRate() == m_proposedRate) {
|
|
|
|
mode = testMode;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-13 19:30:51 +02:00
|
|
|
|
2022-11-06 12:47:21 +02:00
|
|
|
// if no output was connected, set the mode to None
|
|
|
|
if (!m_connectedOutputs.count()) {
|
|
|
|
mode = RandRMode();
|
|
|
|
} else if (!mode.isValid()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode.isValid())
|
|
|
|
{
|
|
|
|
if (m_currentRotation == m_proposedRotation ||
|
|
|
|
(m_currentRotation == RandR::Rotate0 && m_proposedRotation == RandR::Rotate180) ||
|
|
|
|
(m_currentRotation == RandR::Rotate180 && m_proposedRotation == RandR::Rotate0) ||
|
|
|
|
(m_currentRotation == RandR::Rotate90 && m_proposedRotation == RandR::Rotate270) ||
|
|
|
|
(m_currentRotation == RandR::Rotate270 && m_proposedRotation == RandR::Rotate90)) {
|
|
|
|
QRect r = QRect(0,0,0,0).united(m_proposedRect);
|
|
|
|
if (r.width() > m_screen->maxSize().width() || r.height() > m_screen->maxSize().height()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the desired mode is bigger than the current screen size, first change the
|
|
|
|
// screen size, and then the crtc size
|
|
|
|
if (!m_screen->rect().contains(r)) {
|
|
|
|
// try to adjust the screen size
|
|
|
|
if (!m_screen->adjustSize(r)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
QRect r(m_proposedRect.topLeft(), QSize(m_proposedRect.height(), m_proposedRect.width()));
|
|
|
|
if (!m_screen->rect().contains(r)) {
|
|
|
|
// check if the rotated rect is smaller than the max screen size
|
|
|
|
r = m_screen->rect().united(r);
|
|
|
|
if (r.width() > m_screen->maxSize().width() || r.height() > m_screen->maxSize().height()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust the screen size
|
|
|
|
r = r.united(m_currentRect);
|
|
|
|
if (!m_screen->adjustSize(r)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RROutput *outputs = new RROutput[m_connectedOutputs.count()];
|
|
|
|
for (int i = 0; i < m_connectedOutputs.count(); ++i) {
|
|
|
|
outputs[i] = m_connectedOutputs.at(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
Status s = XRRSetCrtcConfig(QX11Info::display(), m_screen->resources(), m_id,
|
|
|
|
RandR::timestamp, m_proposedRect.x(), m_proposedRect.y(), mode.id(),
|
|
|
|
m_proposedRotation, outputs, m_connectedOutputs.count());
|
|
|
|
|
|
|
|
delete[] outputs;
|
|
|
|
|
|
|
|
bool ret = false;
|
|
|
|
if (s == RRSetConfigSuccess) {
|
|
|
|
kDebug() << "Changes for CRTC" << m_id << "successfully applied.";
|
|
|
|
m_currentMode = mode.id();
|
|
|
|
m_currentRotation = m_proposedRotation;
|
|
|
|
m_currentRect = m_proposedRect;
|
|
|
|
m_currentRate = mode.refreshRate();
|
|
|
|
emit crtcChanged(m_id, RandR::ChangeMode);
|
|
|
|
ret = true;
|
|
|
|
} else {
|
|
|
|
kDebug() << "Failed to apply changes for CRTC" << m_id;
|
|
|
|
ret = false;
|
|
|
|
// Invalidate the XRRScreenResources cache
|
|
|
|
if (s == RRSetConfigInvalidConfigTime) {
|
|
|
|
m_screen->loadSettings(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_screen->adjustSize();
|
|
|
|
return ret;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::proposeSize(const QSize &s)
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
m_proposedRect.setSize(s);
|
|
|
|
m_proposedRate = 0;
|
|
|
|
return true;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::proposePosition(const QPoint &p)
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
m_proposedRect.moveTopLeft(p);
|
|
|
|
return true;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::proposeRotation(int rotation)
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
// check if this crtc supports the asked rotation
|
|
|
|
if (!rotation && m_rotations) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-11-13 19:30:51 +02:00
|
|
|
|
2022-11-03 14:20:15 +02:00
|
|
|
m_proposedRotation = rotation;
|
|
|
|
return true;
|
2014-11-13 19:30:51 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::proposeRefreshRate(float rate)
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
m_proposedRate = rate;
|
|
|
|
return true;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RandRCrtc::proposeOriginal()
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
m_proposedRotation = m_originalRotation;
|
|
|
|
m_proposedRect = m_originalRect;
|
|
|
|
m_proposedRate = m_originalRate;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void RandRCrtc::setOriginal()
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
m_originalRotation = m_currentRotation;
|
|
|
|
m_originalRect = m_currentRect;
|
|
|
|
m_originalRate = m_currentRate;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::proposedChanged()
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return (m_proposedRotation != m_currentRotation ||
|
|
|
|
m_proposedRect != m_currentRect ||
|
|
|
|
m_proposedRate != m_currentRate);
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::addOutput(RROutput output, const QSize &s)
|
|
|
|
{
|
2022-11-06 12:47:21 +02:00
|
|
|
QSize size = s;
|
|
|
|
// if no mode was given, use the current one
|
|
|
|
if (!size.isValid()) {
|
|
|
|
size = m_currentRect.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if this output is not already on this crtc
|
|
|
|
// if not, add it
|
|
|
|
if (m_connectedOutputs.indexOf(output) == -1) {
|
|
|
|
// the given output is not possible
|
|
|
|
if (m_possibleOutputs.indexOf(output) == -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_connectedOutputs.append(output);
|
|
|
|
}
|
|
|
|
m_proposedRect = QRect(m_proposedRect.topLeft(), s);
|
|
|
|
return true;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RandRCrtc::removeOutput(RROutput output)
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
int index = m_connectedOutputs.indexOf(output);
|
|
|
|
if (index == -1) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-11-13 19:30:51 +02:00
|
|
|
|
2022-11-03 14:20:15 +02:00
|
|
|
m_connectedOutputs.removeAt(index);
|
|
|
|
return true;
|
2022-11-06 12:47:21 +02:00
|
|
|
}
|
2014-11-13 19:30:51 +02:00
|
|
|
|
|
|
|
OutputList RandRCrtc::connectedOutputs() const
|
|
|
|
{
|
2022-11-03 14:20:15 +02:00
|
|
|
return m_connectedOutputs;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ModeList RandRCrtc::modes() const
|
2022-11-03 14:20:15 +02:00
|
|
|
{
|
|
|
|
ModeList modeList;
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
foreach(RROutput o, m_connectedOutputs) {
|
|
|
|
RandROutput *output = m_screen->output(o);
|
|
|
|
if (first) {
|
|
|
|
modeList = output->modes();
|
|
|
|
first = false;
|
|
|
|
} else {
|
2022-11-03 14:24:31 +02:00
|
|
|
QMutableListIterator<RRMode> it(modeList);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
const RRMode m = it.next();
|
2022-11-03 14:20:15 +02:00
|
|
|
if (output->modes().indexOf(m) == -1) {
|
2022-11-03 14:24:31 +02:00
|
|
|
it.remove();
|
2022-11-03 14:20:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return modeList;
|
2014-11-13 19:30:51 +02:00
|
|
|
}
|
|
|
|
|
2015-02-27 09:28:46 +00:00
|
|
|
#include "moc_randrcrtc.cpp"
|
2014-11-13 19:30:51 +02:00
|
|
|
|
|
|
|
|