2
* Copyright (c) 2007 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
#include "randrcrtc.h"
20
#include "randrscreen.h"
21
#include "randroutput.h"
22
#include "randrmode.h"
24
RandRCrtc::RandRCrtc(RandRScreen *parent, RRCrtc id)
26
m_currentRect(0, 0, 0, 0),
27
m_originalRect(m_currentRect),
28
m_proposedRect(m_originalRect)
33
m_currentRotation = m_originalRotation = m_proposedRotation = RandR::Rotate0;
34
m_currentRate = m_originalRate = m_proposedRate = 0;
36
m_rotations = RandR::Rotate0;
41
RandRCrtc::~RandRCrtc()
46
RRCrtc RandRCrtc::id() const
51
int RandRCrtc::rotations() const
56
int RandRCrtc::rotation() const
58
return m_currentRotation;
61
bool RandRCrtc::isValid(void) const
66
void RandRCrtc::loadSettings(bool notify)
71
kDebug() << "Querying information about CRTC" << m_id;
74
XRRCrtcInfo *info = XRRGetCrtcInfo(QX11Info::display(), m_screen->resources(), m_id);
77
if (RandR::timestamp != info->timestamp)
78
RandR::timestamp = info->timestamp;
80
QRect rect = QRect(info->x, info->y, info->width, info->height);
81
if (rect != m_currentRect)
84
changes |= RandR::ChangeRect;
87
// get all connected outputs
88
// and create a list of modes that are available in all connected outputs
91
for (int i = 0; i < info->noutput; ++i) {
92
outputs.append(info->outputs[i]);
95
// check if the list changed from the original one
96
if (outputs != m_connectedOutputs)
98
changes |= RandR::ChangeOutputs;
99
m_connectedOutputs = outputs;
102
// get all outputs this crtc can be connected to
104
for (int i = 0; i < info->npossible; ++i)
105
outputs.append(info->possible[i]);
107
if (outputs != m_possibleOutputs)
109
changes |= RandR::ChangeOutputs;
110
m_possibleOutputs = outputs;
114
m_rotations = info->rotations;
115
if (m_currentRotation != info->rotation)
117
m_currentRotation = info->rotation;
118
changes |= RandR::ChangeRotation;
121
// check if the current mode has changed
122
if (m_currentMode != info->mode)
124
m_currentMode = info->mode;
125
changes |= RandR::ChangeMode;
128
RandRMode m = m_screen->mode(m_currentMode);
129
if (m_currentRate != m.refreshRate())
131
m_currentRate = m.refreshRate();
132
changes |= RandR::ChangeRate;
135
// just to make sure it gets initialized
136
m_proposedRect = m_currentRect;
137
m_proposedRotation = m_currentRotation;
138
m_proposedRate = m_currentRate;
141
XRRFreeCrtcInfo(info);
143
if (changes && notify)
144
emit crtcChanged(m_id, changes);
147
void RandRCrtc::handleEvent(XRRCrtcChangeNotifyEvent *event)
149
kDebug() << "[CRTC] Event...";
152
if (event->mode != m_currentMode)
154
kDebug() << " Changed mode";
155
changed |= RandR::ChangeMode;
156
m_currentMode = event->mode;
159
if (event->rotation != m_currentRotation)
161
kDebug() << " Changed rotation: " << event->rotation;
162
changed |= RandR::ChangeRotation;
163
m_currentRotation = event->rotation;
165
if (event->x != m_currentRect.x() || event->y != m_currentRect.y())
167
kDebug() << " Changed position: " << event->x << "," << event->y;
168
changed |= RandR::ChangeRect;
169
m_currentRect.moveTopLeft(QPoint(event->x, event->y));
172
RandRMode mode = m_screen->mode(m_currentMode);
173
if (mode.size() != m_currentRect.size())
175
kDebug() << " Changed size: " << mode.size();
176
changed |= RandR::ChangeRect;
177
m_currentRect.setSize(mode.size());
178
//Do NOT use event->width and event->height here, as it is being returned wrongly
182
emit crtcChanged(m_id, changed);
185
RandRMode RandRCrtc::mode() const
187
return m_screen->mode(m_currentMode);
190
QRect RandRCrtc::rect() const
192
return m_currentRect;
195
float RandRCrtc::refreshRate() const
197
return m_currentRate;
200
bool RandRCrtc::applyProposed()
202
kDebug() << "Applying proposed changes for CRTC" << m_id << "...";
203
kDebug() << " Current Screen rect:" << m_screen->rect();
204
kDebug() << " Current CRTC rect:" << m_currentRect;
205
kDebug() << " Current rotation:" << m_currentRotation;
206
kDebug() << " Proposed CRTC rect:" << m_proposedRect;
207
kDebug() << " Proposed rotation:" << m_proposedRotation;
208
kDebug() << " Proposed refresh rate:" << m_proposedRate;
209
kDebug() << " Enabled outputs:";
210
if (m_connectedOutputs.isEmpty())
211
kDebug() << " - none";
212
for (int i = 0; i < m_connectedOutputs.count(); ++i)
213
kDebug() << " -" << m_screen->output(m_connectedOutputs.at(i))->name();
216
if (m_proposedRect.size() == m_currentRect.size() && m_proposedRate == m_currentRate)
218
mode = m_screen->mode(m_currentMode);
222
// find a mode that has the desired size and is supported
223
// by all connected outputs
224
ModeList modeList = modes();
227
foreach(RRMode m, modeList)
229
RandRMode mode = m_screen->mode(m);
230
if (mode.size() == m_proposedRect.size())
231
matchModes.append(m);
234
// if no matching modes were found, disable output
235
// else set the mode to the first mode in the list. If no refresh rate was given
236
// or no mode was found matching the given refresh rate, the first mode of the
238
if (!matchModes.count())
241
mode = m_screen->mode(matchModes.first());
243
foreach(RRMode m, matchModes)
245
RandRMode testMode = m_screen->mode(m);
246
if (testMode.refreshRate() == m_proposedRate)
254
// if no output was connected, set the mode to None
255
if (!m_connectedOutputs.count())
257
else if (!mode.isValid())
262
if (m_currentRotation == m_proposedRotation ||
263
(m_currentRotation == RandR::Rotate0 && m_proposedRotation == RandR::Rotate180) ||
264
(m_currentRotation == RandR::Rotate180 && m_proposedRotation == RandR::Rotate0) ||
265
(m_currentRotation == RandR::Rotate90 && m_proposedRotation == RandR::Rotate270) ||
266
(m_currentRotation == RandR::Rotate270 && m_proposedRotation == RandR::Rotate90))
268
QRect r = QRect(0,0,0,0).united(m_proposedRect);
269
if (r.width() > m_screen->maxSize().width() || r.height() > m_screen->maxSize().height())
272
// if the desired mode is bigger than the current screen size, first change the
273
// screen size, and then the crtc size
274
if (!m_screen->rect().contains(r))
276
// try to adjust the screen size
277
if (!m_screen->adjustSize(r))
285
QRect r(m_proposedRect.topLeft(), QSize(m_proposedRect.height(), m_proposedRect.width()));
286
if (!m_screen->rect().contains(r))
288
// check if the rotated rect is smaller than the max screen size
289
r = m_screen->rect().united(r);
290
if (r.width() > m_screen->maxSize().width() || r.height() > m_screen->maxSize().height())
293
// adjust the screen size
294
r = r.united(m_currentRect);
295
if (!m_screen->adjustSize(r))
301
RROutput *outputs = new RROutput[m_connectedOutputs.count()];
302
for (int i = 0; i < m_connectedOutputs.count(); ++i)
303
outputs[i] = m_connectedOutputs.at(i);
305
Status s = XRRSetCrtcConfig(QX11Info::display(), m_screen->resources(), m_id,
306
RandR::timestamp, m_proposedRect.x(), m_proposedRect.y(), mode.id(),
307
m_proposedRotation, outputs, m_connectedOutputs.count());
312
if (s == RRSetConfigSuccess)
314
kDebug() << "Changes for CRTC" << m_id << "successfully applied.";
315
m_currentMode = mode.id();
316
m_currentRotation = m_proposedRotation;
317
m_currentRect = m_proposedRect;
318
m_currentRate = mode.refreshRate();
319
emit crtcChanged(m_id, RandR::ChangeMode);
324
kDebug() << "Failed to apply changes for CRTC" << m_id;
326
// Invalidate the XRRScreenResources cache
327
if(s == RRSetConfigInvalidConfigTime)
328
m_screen->loadSettings(true);
331
m_screen->adjustSize();
335
bool RandRCrtc::proposeSize(const QSize &s)
337
m_proposedRect.setSize(s);
342
bool RandRCrtc::proposePosition(const QPoint &p)
344
m_proposedRect.moveTopLeft(p);
348
bool RandRCrtc::proposeRotation(int rotation)
350
// check if this crtc supports the asked rotation
351
if (!rotation & m_rotations)
354
m_proposedRotation = rotation;
359
bool RandRCrtc::proposeRefreshRate(float rate)
361
m_proposedRate = rate;
365
void RandRCrtc::proposeOriginal()
367
m_proposedRotation = m_originalRotation;
368
m_proposedRect = m_originalRect;
369
m_proposedRate = m_originalRate;
372
void RandRCrtc::setOriginal()
374
m_originalRotation = m_currentRotation;
375
m_originalRect = m_currentRect;
376
m_originalRate = m_currentRate;
379
bool RandRCrtc::proposedChanged()
381
return (m_proposedRotation != m_currentRotation ||
382
m_proposedRect != m_currentRect ||
383
m_proposedRate != m_currentRate);
386
bool RandRCrtc::addOutput(RROutput output, const QSize &s)
389
// if no mode was given, use the current one
391
size = m_currentRect.size();
393
// check if this output is not already on this crtc
395
if (m_connectedOutputs.indexOf(output) == -1)
397
// the given output is not possible
398
if (m_possibleOutputs.indexOf(output) == -1)
401
m_connectedOutputs.append(output);
403
m_proposedRect = QRect(m_proposedRect.topLeft(), s);
407
bool RandRCrtc::removeOutput(RROutput output)
409
int index = m_connectedOutputs.indexOf(output);
413
m_connectedOutputs.removeAt(index);
417
OutputList RandRCrtc::connectedOutputs() const
419
return m_connectedOutputs;
422
ModeList RandRCrtc::modes() const
428
foreach(RROutput o, m_connectedOutputs)
430
RandROutput *output = m_screen->output(o);
433
modeList = output->modes();
438
foreach(RRMode m, modeList)
440
if (output->modes().indexOf(m) == -1)
441
modeList.removeAll(m);
449
#include "randrcrtc.moc"