add more spacing
[personal-kdebase.git] / workspace / libs / kephal / xrandr12 / randrcrtc.cpp
blob9d1708ebae209b0566354bf355623ea4a2d55281
1 /*
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)
25 : QObject(parent),
26 m_currentRect(0, 0, 0, 0),
27 m_originalRect(m_currentRect),
28 m_proposedRect(m_originalRect)
30 m_screen = parent;
31 Q_ASSERT(m_screen);
33 m_currentRotation = m_originalRotation = m_proposedRotation = RandR::Rotate0;
34 m_currentRate = m_originalRate = m_proposedRate = 0;
35 m_currentMode = 0;
36 m_rotations = RandR::Rotate0;
38 m_id = id;
41 RandRCrtc::~RandRCrtc()
43 // do nothing for now
46 RRCrtc RandRCrtc::id() const
48 return m_id;
51 int RandRCrtc::rotations() const
53 return m_rotations;
56 int RandRCrtc::rotation() const
58 return m_currentRotation;
61 bool RandRCrtc::isValid(void) const
63 return m_id != None;
66 void RandRCrtc::loadSettings(bool notify)
68 if(m_id == None)
69 return;
71 int changes = 0;
72 XRRCrtcInfo *info = XRRGetCrtcInfo(QX11Info::display(), m_screen->resources(), m_id);
73 Q_ASSERT(info);
75 if (RandR::timestamp != info->timestamp)
76 RandR::timestamp = info->timestamp;
78 QRect rect = QRect(info->x, info->y, info->width, info->height);
79 if (rect != m_currentRect)
81 m_currentRect = rect;
82 changes |= RandR::ChangeRect;
85 // get all connected outputs
86 // and create a list of modes that are available in all connected outputs
87 OutputList outputs;
89 for (int i = 0; i < info->noutput; ++i)
90 outputs.append(info->outputs[i]);
92 // check if the list changed from the original one
93 if (outputs != m_connectedOutputs)
95 changes |= RandR::ChangeOutputs;
96 m_connectedOutputs = outputs;
99 // get all outputs this crtc can be connected to
100 outputs.clear();
101 for (int i = 0; i < info->npossible; ++i)
102 outputs.append(info->possible[i]);
104 if (outputs != m_possibleOutputs)
106 changes |= RandR::ChangeOutputs;
107 m_possibleOutputs = outputs;
109 //qDebug() << "loaded possible outputs:" << m_id << m_possibleOutputs;
111 // get all rotations
112 m_rotations = info->rotations;
113 if (m_currentRotation != info->rotation)
115 m_currentRotation = info->rotation;
116 changes |= RandR::ChangeRotation;
119 // check if the current mode has changed
120 if (m_currentMode != info->mode)
122 m_currentMode = info->mode;
123 changes |= RandR::ChangeMode;
126 RandRMode m = m_screen->mode(m_currentMode);
127 if (m_currentRate != m.refreshRate())
129 m_currentRate = m.refreshRate();
130 changes |= RandR::ChangeRate;
133 // just to make sure it gets initialized
134 m_proposedRect = m_currentRect;
135 m_proposedRotation = m_currentRotation;
136 m_proposedRate = m_currentRate;
138 // free the info
139 XRRFreeCrtcInfo(info);
141 if (changes && notify)
142 emit crtcChanged(m_id, changes);
145 void RandRCrtc::handleEvent(XRRCrtcChangeNotifyEvent *event)
147 qDebug() << "[CRTC" << m_id << "] Event...";
148 qDebug() << " mode: " << event->mode << "(current " << m_currentMode << ")";
149 qDebug() << " pos: (" << event->x << "," << event->y << ")";
150 qDebug() << " size: " << event->width << "x" << event->height;
151 qDebug() << " rotation: " << event->rotation;
153 int changed = 0;
155 if (event->mode != m_currentMode)
157 qDebug() << " Changed mode - old " << m_currentMode << " - new " << event->mode;
158 changed |= RandR::ChangeMode;
159 m_currentMode = event->mode;
162 if (event->rotation != m_currentRotation)
164 qDebug() << " Changed rotation: " << event->rotation;
165 changed |= RandR::ChangeRotation;
166 m_currentRotation = event->rotation;
168 if (event->x != m_currentRect.x() || event->y != m_currentRect.y())
170 qDebug() << " Changed position: " << event->x << "," << event->y;
171 changed |= RandR::ChangeRect;
172 m_currentRect.moveTopLeft(QPoint(event->x, event->y));
175 RandRMode mode = m_screen->mode(m_currentMode);
176 QSize newSize = mode.size();
178 if (m_currentRotation == RandR::Rotate90 || m_currentRotation == RandR::Rotate270)
180 // in rotated modes leaving the screen on its "side" exchange width<->height
181 newSize = QSize(newSize.height(), newSize.width());
184 if (newSize != m_currentRect.size())
186 qDebug() << " Changed size: " << mode.size();
187 changed |= RandR::ChangeRect;
188 m_currentRect.setSize(mode.size());
189 //Do NOT use event->width and event->height here, as it is being returned wrongly
192 if (changed)
193 emit crtcChanged(m_id, changed);
196 RandRMode RandRCrtc::mode() const
198 return m_screen->mode(m_currentMode);
201 QRect RandRCrtc::rect() const
203 return m_currentRect;
206 float RandRCrtc::refreshRate() const
208 return m_currentRate;
211 bool RandRCrtc::applyProposed()
213 qDebug() << "[CRTC] Going to apply (" << m_id << ") ....";
214 qDebug() << " Current Screen rect: " << m_screen->rect();
215 qDebug() << " Current CRTC Rect: " << m_currentRect;
216 qDebug() << " Current Rotation: " << m_currentRotation;
217 qDebug() << " Proposed rect: " << m_proposedRect;
218 qDebug() << " Proposed rotation: " << m_proposedRotation;
219 qDebug() << " Proposed refresh rate: " << m_proposedRate;
220 qDebug() << " Outputs: ";
221 for (int i = 0; i < m_connectedOutputs.count(); ++i)
222 qDebug() << " - " << m_screen->output(m_connectedOutputs.at(i))->name();
224 RandRMode mode;
225 if (m_proposedRect.size() == m_currentRect.size() && m_proposedRate == m_currentRate)
227 mode = m_screen->mode(m_currentMode);
229 else
231 // find a mode that has the desired size and is supported
232 // by all connected outputs
233 ModeList modeList = modes();
234 ModeList matchModes;
236 foreach(const RRMode & m, modeList)
238 RandRMode mode = m_screen->mode(m);
239 if (mode.size() == m_proposedRect.size())
240 matchModes.append(m);
243 // if no matching modes were found, disable output
244 // else set the mode to the first mode in the list. If no refresh rate was given
245 // or no mode was found matching the given refresh rate, the first mode of the
246 // list will be used
247 if (!matchModes.count())
248 mode = RandRMode();
249 else
250 mode = m_screen->mode(matchModes.first());
252 foreach(const RRMode & m, matchModes)
254 RandRMode testMode = m_screen->mode(m);
255 if (testMode.refreshRate() == m_proposedRate)
257 mode = testMode;
258 break;
263 // if no output was connected, set the mode to None
264 if (!m_connectedOutputs.count())
265 mode = RandRMode();
266 else if (!mode.isValid())
267 return false;
269 RROutput *outputs = new RROutput[m_connectedOutputs.count()];
270 for (int i = 0; i < m_connectedOutputs.count(); ++i)
271 outputs[i] = m_connectedOutputs.at(i);
273 if (mode.isValid())
275 int currentRotation = m_currentRotation & RandR::RotateMask;
276 int proposedRotation = m_proposedRotation & RandR::RotateMask;
277 if (currentRotation == proposedRotation ||
278 (currentRotation == RandR::Rotate0 && proposedRotation == RandR::Rotate180) ||
279 (currentRotation == RandR::Rotate180 && proposedRotation == RandR::Rotate0) ||
280 (currentRotation == RandR::Rotate90 && proposedRotation == RandR::Rotate270) ||
281 (currentRotation == RandR::Rotate270 && proposedRotation == RandR::Rotate90))
283 QRect r = QRect(0,0,0,0).united(m_proposedRect);
284 if (r.width() > m_screen->maxSize().width() || r.height() > m_screen->maxSize().height())
285 return false;
287 // if the desired mode is bigger than the current screen size, first change the
288 // screen size, and then the crtc size
289 if (!m_screen->rect().contains(r))
291 // try to adjust the screen size
292 if (!m_screen->adjustSize(r))
293 return false;
297 else
300 QRect r(m_proposedRect.topLeft(), QSize(m_proposedRect.height(), m_proposedRect.width()));
301 if (!m_screen->rect().contains(r))
303 // check if the rotated rect is smaller than the max screen size
304 r = m_screen->rect().united(r);
305 if (r.width() > m_screen->maxSize().width() || r.height() > m_screen->maxSize().height())
306 return false;
308 // adjust the screen size
309 r = r.united(m_currentRect);
310 if (!m_screen->adjustSize(r))
311 return false;
317 qDebug() << "calling XRRSetCrtcConfig()";
318 Status s = XRRSetCrtcConfig(QX11Info::display(), m_screen->resources(), m_id,
319 RandR::timestamp, m_proposedRect.x(), m_proposedRect.y(), mode.id(),
320 m_proposedRotation, outputs, m_connectedOutputs.count());
322 delete[] outputs;
324 bool ret;
325 if (s == RRSetConfigSuccess)
327 m_currentMode = mode.id();
328 m_currentRotation = m_proposedRotation;
329 m_currentRect = m_proposedRect;
330 m_currentRate = mode.refreshRate();
331 emit crtcChanged(m_id, RandR::ChangeMode);
332 ret = true;
334 else
336 ret = false;
337 // Invalidate the XRRScreenResources cache
338 if(s == RRSetConfigInvalidConfigTime)
339 m_screen->loadSettings(true);
342 m_screen->adjustSize();
343 return ret;
346 bool RandRCrtc::proposeSize(const QSize &s)
348 m_proposedRect.setSize(s);
349 m_proposedRate = 0;
350 return true;
353 bool RandRCrtc::proposePosition(const QPoint &p)
355 m_proposedRect.moveTopLeft(p);
356 return true;
359 bool RandRCrtc::proposeRotation(int rotation)
361 // check if this crtc supports the asked rotation
362 if (!rotation & m_rotations)
363 return false;
365 m_proposedRotation = rotation;
366 return true;
370 bool RandRCrtc::proposeRefreshRate(float rate)
372 m_proposedRate = rate;
373 return true;
376 void RandRCrtc::proposeOriginal()
378 m_proposedRotation = m_originalRotation;
379 m_proposedRect = m_originalRect;
380 m_proposedRate = m_originalRate;
383 void RandRCrtc::setOriginal()
385 m_originalRotation = m_currentRotation;
386 m_originalRect = m_currentRect;
387 m_originalRate = m_currentRate;
390 bool RandRCrtc::proposedChanged()
392 return (m_proposedRotation != m_currentRotation ||
393 m_proposedRect != m_currentRect ||
394 m_proposedRate != m_currentRate);
397 bool RandRCrtc::addOutput(RROutput output, const QSize &s)
399 QSize size = s;
400 // if no mode was given, use the current one
401 if (!size.isValid())
402 size = m_currentRect.size();
404 // check if this output is not already on this crtc
405 // if not, add it
406 if (m_connectedOutputs.indexOf(output) == -1)
408 qDebug() << "possible:" << m_possibleOutputs;
409 // the given output is not possible
410 if (m_possibleOutputs.indexOf(output) == -1)
411 return false;
413 m_connectedOutputs.append(output);
415 m_proposedRect = QRect(m_proposedRect.topLeft(), s);
416 return true;
419 bool RandRCrtc::removeOutput(RROutput output)
421 int index = m_connectedOutputs.indexOf(output);
422 if (index == -1)
423 return false;
425 m_connectedOutputs.removeAt(index);
426 return true;
429 OutputList RandRCrtc::connectedOutputs() const
431 return m_connectedOutputs;
434 ModeList RandRCrtc::modes() const
436 ModeList modeList;
438 bool first = true;
440 foreach(const RROutput & o, m_connectedOutputs)
442 RandROutput *output = m_screen->output(o);
443 if (first)
445 modeList = output->modes();
446 first = false;
448 else
450 foreach(const RRMode & m, modeList)
452 if (output->modes().indexOf(m) == -1)
453 modeList.removeAll(m);
458 return modeList;