not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kcontrol / randr / randrcrtc.cpp
blobd3dbe82d7d0b21f7dba2e190f2cb28b5c8826e0a
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 kDebug() << "Querying information about CRTC" << m_id;
73 int changes = 0;
74 XRRCrtcInfo *info = XRRGetCrtcInfo(QX11Info::display(), m_screen->resources(), m_id);
75 Q_ASSERT(info);
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)
83 m_currentRect = rect;
84 changes |= RandR::ChangeRect;
87 // get all connected outputs
88 // and create a list of modes that are available in all connected outputs
89 OutputList 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
103 outputs.clear();
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;
113 // get all rotations
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;
140 // free the info
141 XRRFreeCrtcInfo(info);
143 if (changes && notify)
144 emit crtcChanged(m_id, changes);
147 void RandRCrtc::handleEvent(XRRCrtcChangeNotifyEvent *event)
149 kDebug() << "[CRTC] Event...";
150 int changed = 0;
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
181 if (changed)
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();
215 RandRMode mode;
216 if (m_proposedRect.size() == m_currentRect.size() && m_proposedRate == m_currentRate)
218 mode = m_screen->mode(m_currentMode);
220 else
222 // find a mode that has the desired size and is supported
223 // by all connected outputs
224 ModeList modeList = modes();
225 ModeList matchModes;
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
237 // list will be used
238 if (!matchModes.count())
239 mode = RandRMode();
240 else
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)
248 mode = testMode;
249 break;
254 // if no output was connected, set the mode to None
255 if (!m_connectedOutputs.count())
256 mode = RandRMode();
257 else if (!mode.isValid())
258 return false;
260 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())
270 return false;
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))
278 return false;
282 else
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())
291 return false;
293 // adjust the screen size
294 r = r.united(m_currentRect);
295 if (!m_screen->adjustSize(r))
296 return false;
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());
309 delete[] outputs;
311 bool ret;
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);
320 ret = true;
322 else
324 kDebug() << "Failed to apply changes for CRTC" << m_id;
325 ret = false;
326 // Invalidate the XRRScreenResources cache
327 if(s == RRSetConfigInvalidConfigTime)
328 m_screen->loadSettings(true);
331 m_screen->adjustSize();
332 return ret;
335 bool RandRCrtc::proposeSize(const QSize &s)
337 m_proposedRect.setSize(s);
338 m_proposedRate = 0;
339 return true;
342 bool RandRCrtc::proposePosition(const QPoint &p)
344 m_proposedRect.moveTopLeft(p);
345 return true;
348 bool RandRCrtc::proposeRotation(int rotation)
350 // check if this crtc supports the asked rotation
351 if (!rotation & m_rotations)
352 return false;
354 m_proposedRotation = rotation;
355 return true;
359 bool RandRCrtc::proposeRefreshRate(float rate)
361 m_proposedRate = rate;
362 return true;
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)
388 QSize size = s;
389 // if no mode was given, use the current one
390 if (!size.isValid())
391 size = m_currentRect.size();
393 // check if this output is not already on this crtc
394 // if not, add it
395 if (m_connectedOutputs.indexOf(output) == -1)
397 // the given output is not possible
398 if (m_possibleOutputs.indexOf(output) == -1)
399 return false;
401 m_connectedOutputs.append(output);
403 m_proposedRect = QRect(m_proposedRect.topLeft(), s);
404 return true;
407 bool RandRCrtc::removeOutput(RROutput output)
409 int index = m_connectedOutputs.indexOf(output);
410 if (index == -1)
411 return false;
413 m_connectedOutputs.removeAt(index);
414 return true;
417 OutputList RandRCrtc::connectedOutputs() const
419 return m_connectedOutputs;
422 ModeList RandRCrtc::modes() const
424 ModeList modeList;
426 bool first = true;
428 foreach(RROutput o, m_connectedOutputs)
430 RandROutput *output = m_screen->output(o);
431 if (first)
433 modeList = output->modes();
434 first = false;
436 else
438 foreach(RRMode m, modeList)
440 if (output->modes().indexOf(m) == -1)
441 modeList.removeAll(m);
446 return modeList;
449 #include "randrcrtc.moc"