add more spacing
[personal-kdebase.git] / workspace / libs / kephal / xrandr12 / randroutput.cpp
blobec719acb72783156a9df5646339be473e1b2497c
1 /*
2 * Copyright (c) 2007 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
3 * Copyright (c) 2007, 2008 Harry Bock <hbock@providence.edu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "randroutput.h"
21 #include "randrscreen.h"
22 #include "randrcrtc.h"
23 #include "randrmode.h"
25 #include <QX11Info>
28 RandROutput::RandROutput(RandRScreen *parent, RROutput id)
29 : QObject(parent)
31 m_screen = parent;
32 Q_ASSERT(m_screen);
34 m_id = id;
35 m_crtc = 0;
36 m_rotations = 0;
38 queryOutputInfo();
40 m_proposedRotation = m_originalRotation;
41 m_proposedRate = m_originalRate;
42 m_proposedRect = m_originalRect;
45 RandROutput::~RandROutput()
49 RROutput RandROutput::id() const
51 return m_id;
54 RandRScreen *RandROutput::screen() const
56 return m_screen;
59 bool RandROutput::queryOutputInfo(void)
61 XRROutputInfo *info = XRRGetOutputInfo(QX11Info::display(), m_screen->resources(), m_id);
62 Q_ASSERT(info);
64 bool changes = false;
65 if (RandR::timestamp != info->timestamp) {
66 RandR::timestamp = info->timestamp;
67 //changes = true;
70 // Set up the output's connection status, name, and current
71 // CRT controller.
72 bool pConn = m_connected;
73 m_connected = (info->connection == RR_Connected);
74 if (pConn != m_connected) {
75 changes = true;
77 m_name = info->name;
79 setCrtc(m_screen->crtc(info->crtc));
80 m_crtc->loadSettings(false);
82 for(int i = 0; i < info->ncrtc; ++i)
83 m_possibleCrtcs.append(info->crtcs[i]);
85 //TODO: is it worth notifying changes on mode list changing?
86 m_modes.clear();
87 m_preferredMode = m_screen->mode(info->modes[info->npreferred]);
89 for (int i = 0; i < info->nmode; ++i)
90 m_modes.append(info->modes[i]);
92 //get all possible rotations
93 m_rotations = 0;
94 for (int i = 0; i < m_possibleCrtcs.count(); ++i)
96 RandRCrtc *crtc = m_screen->crtc(m_possibleCrtcs.at(i));
97 Q_ASSERT(crtc);
98 m_rotations |= crtc->rotations();
100 m_originalRotation = m_crtc->rotation();
101 m_originalRate = m_crtc->refreshRate();
102 m_originalRect = m_crtc->rect();
104 if(isConnected()) {
105 qDebug() << "Output name:" << m_name;
106 qDebug() << "Output refresh rate:" << m_originalRate;
107 qDebug() << "Output rect:" << m_originalRect;
108 qDebug() << "Output rotation:" << m_originalRotation;
111 XRRFreeOutputInfo(info);
113 return changes;
116 void RandROutput::loadSettings(bool notify)
118 Q_UNUSED(notify);
119 queryOutputInfo();
121 qDebug() << "STUB: calling queryOutputInfo instead. Check if this has "
122 << "any undesired effects. ";
125 void RandROutput::handleEvent(XRROutputChangeNotifyEvent *event)
127 int changed = 0;
129 qDebug() << "[OUTPUT" << m_id << "] Got event for " << m_name;
130 qDebug() << " crtc: " << event->crtc << "(current " << m_crtc->id() << ")";
131 qDebug() << " mode: " << event->mode << "(current " << mode().id() << ")";
132 qDebug() << " rotation: " << event->rotation;
133 qDebug() << " connection: " << event->connection;
135 //FIXME: handling these events incorrectly, causing an X11 I/O error...
136 // Disable for now.
137 //qWarning() << "FIXME: Output event ignored!";
138 //return;
140 RRCrtc currentCrtc = m_crtc->id();
141 if (event->crtc != currentCrtc)
143 changed |= RandR::ChangeCrtc;
144 // update crtc settings
145 if (currentCrtc != None)
146 m_crtc->loadSettings(true);
147 //m_screen->crtc(m_currentCrtc)->loadSettings(true);
148 setCrtc(m_screen->crtc(event->crtc));
149 if (currentCrtc != None)
150 m_crtc->loadSettings(true);
153 if (event->mode != mode().id())
154 changed |= RandR::ChangeMode;
156 if (event->rotation != rotation())
157 changed |= RandR::ChangeRotation;
159 if((event->connection == RR_Connected) != m_connected)
161 changed |= RandR::ChangeConnection;
162 m_connected = (event->connection == RR_Connected);
163 if (!m_connected && currentCrtc != None)
164 m_crtc = m_screen->crtc(None);
167 if(changed)
168 emit outputChanged(m_id, changed);
171 void RandROutput::handlePropertyEvent(XRROutputPropertyNotifyEvent *event)
173 // TODO: Do something with this!
174 // By perusing thru some XOrg drivers, some of the properties that can
175 // are configured through XRANDR are:
176 // - LVDS Backlights
177 // - TV output formats
179 char *name = XGetAtomName(QX11Info::display(), event->property);
180 qDebug() << "Got XRROutputPropertyNotifyEvent for property Atom " << name;
181 XFree(name);
184 QString RandROutput::name() const
186 return m_name;
189 QString RandROutput::icon() const
191 // FIXME: check what names we should use and what kind of outputs randr can
192 // report. It would also be interesting to be able to get the monitor name
193 // using EDID or something like that, just don't know if it is even possible.
194 if (m_name.contains("VGA"))
195 return "video-display";
196 else if (m_name.contains("LVDS"))
197 return "video-display";
199 // I doubt this is a good choice; can't find anything better in the spec.
200 // video-x-generic might work, but that's a mimetype, which is inappropriate
201 // for an output connection type.
202 else if (m_name.contains("TV"))
203 return "multimedia-player";
205 return "video-display";
208 CrtcList RandROutput::possibleCrtcs() const
210 return m_possibleCrtcs;
213 RandRCrtc *RandROutput::crtc() const
215 return m_crtc;
218 ModeList RandROutput::modes() const
220 return m_modes;
223 RandRMode RandROutput::mode() const
225 if (!isConnected())
226 return None;
228 if (!m_crtc)
229 return RandRMode();
231 return m_crtc->mode();
234 RandRMode RandROutput::preferredMode(void) const
236 return m_preferredMode;
239 SizeList RandROutput::sizes() const
241 SizeList sizeList;
243 foreach(const RRMode & m, m_modes)
245 RandRMode mode = m_screen->mode(m);
246 if (!mode.isValid())
247 continue;
248 if (sizeList.indexOf(mode.size()) == -1)
249 sizeList.append(mode.size());
251 return sizeList;
254 QRect RandROutput::rect() const
256 if (!m_crtc) qDebug() << "No Crtc for output" << m_id;
257 Q_ASSERT(m_crtc);
258 if (!m_crtc->isValid())
259 return QRect(0, 0, 0, 0);
261 return m_crtc->rect();
264 RateList RandROutput::refreshRates(const QSize &s) const
266 RateList list;
267 QSize size = s;
268 if (!size.isValid())
269 size = rect().size();
271 foreach(const RRMode & m, m_modes)
273 RandRMode mode = m_screen->mode(m);
274 if (!mode.isValid())
275 continue;
276 if (mode.size() == size)
277 list.append(mode.refreshRate());
279 return list;
282 float RandROutput::refreshRate() const
284 return m_crtc->mode().refreshRate();
287 int RandROutput::rotations() const
289 return m_rotations;
292 int RandROutput::rotation() const
294 if (!isActive())
295 return RandR::Rotate0;
297 Q_ASSERT(m_crtc);
298 return m_crtc->rotation();
301 bool RandROutput::isConnected() const
303 return m_connected;
306 bool RandROutput::isActive() const
308 return (m_connected && mode().isValid() && m_crtc->id() != None);
311 void RandROutput::proposeOriginal()
313 if (m_crtc->id() != None)
314 m_crtc->proposeOriginal();
317 void RandROutput::proposeRefreshRate(float rate)
319 m_originalRate = refreshRate();
320 m_proposedRate = rate;
323 void RandROutput::proposeRect(const QRect &r)
325 m_originalRect = rect();
326 m_proposedRect = r;
329 void RandROutput::proposeRotation(int r)
331 m_originalRotation = rotation();
332 m_proposedRotation = r;
335 void RandROutput::slotDisable()
337 setCrtc(m_screen->crtc(None));
340 void RandROutput::slotEnable()
342 if(!m_connected)
343 return;
345 qDebug() << "Attempting to enable " << m_name;
346 RandRCrtc *crtc = findEmptyCrtc();
348 if(crtc)
349 setCrtc(crtc);
352 RandRCrtc *RandROutput::findEmptyCrtc()
354 RandRCrtc *crtc = 0;
356 foreach(const RRCrtc & c, m_possibleCrtcs)
358 crtc = m_screen->crtc(c);
359 if (crtc->connectedOutputs().count() == 0)
360 return crtc;
363 return 0;
366 bool RandROutput::tryCrtc(RandRCrtc *crtc, int changes)
368 RandRCrtc *oldCrtc = m_crtc;
370 // if we are not yet using this crtc, switch to use it
371 if (crtc->id() != oldCrtc->id())
372 setCrtc(crtc);
374 crtc->setOriginal();
376 if (changes & RandR::ChangeRect)
378 crtc->proposeSize(m_proposedRect.size());
379 crtc->proposePosition(m_proposedRect.topLeft());
381 if (changes & RandR::ChangeRotation)
382 crtc->proposeRotation(m_proposedRotation);
383 if (changes & RandR::ChangeRate)
384 crtc->proposeRefreshRate(m_proposedRate);
386 if (crtc->applyProposed())
387 return true;
389 // revert changes if we didn't succeed
390 crtc->proposeOriginal();
391 crtc->applyProposed();
393 // switch back to the old crtc
394 setCrtc(oldCrtc);
395 return false;
398 bool RandROutput::setCrtc(RandRCrtc *crtc, bool applyNow)
400 Q_UNUSED(applyNow);
401 if( !crtc || (m_crtc && crtc->id() == m_crtc->id()) )
402 return false;
404 qDebug() << "Setting CRTC" << crtc->id() << "on output" << m_name << "(previous" << (m_crtc ? m_crtc->id() : 0) << ")";
406 if(m_crtc && m_crtc->isValid()) {
407 disconnect(m_crtc, SIGNAL(crtcChanged(RRCrtc, int)),
408 this, SLOT(slotCrtcChanged(RRCrtc, int)));
410 m_crtc->removeOutput(m_id);
411 // m_crtc->applyProposed();
413 m_crtc = crtc;
414 if (!m_crtc->isValid())
415 return false;
417 if (!m_crtc->addOutput(m_id)) {
418 return false;
421 qDebug() << "CRTC outputs:" << m_crtc->connectedOutputs();
422 connect(m_crtc, SIGNAL(crtcChanged(RRCrtc, int)),
423 this, SLOT(slotCrtcChanged(RRCrtc, int)));
425 return true;
428 void RandROutput::slotCrtcChanged(RRCrtc c, int changes)
430 Q_UNUSED(c);
432 //FIXME select which changes we should notify
433 emit outputChanged(m_id, changes);
436 bool RandROutput::applyProposed(int changes)
438 RandRCrtc *crtc;
440 QRect r;
442 if (changes & RandR::ChangeRect)
443 r = m_proposedRect;
446 // first try to apply to the already attached crtc if any
447 if (m_crtc->isValid())
449 crtc = m_crtc;
450 if (tryCrtc(crtc, changes))
452 return true;
454 return false;
457 //then try an empty crtc
458 crtc = findEmptyCrtc();
460 // TODO: check if we can add this output to a CRTC which already has an output
461 // connection
462 if (!crtc)
463 return false;
465 // try the crtc, and if no confirmation is needed or the user confirm, save the new settings
466 if (tryCrtc(crtc, changes))
468 return true;
471 return false;