2 * Copyright (c) 2007 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
3 * Copyright (c) 2007, 2008 Harry Bock <hbock@providence.edu>
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"
28 RandROutput::RandROutput(RandRScreen
*parent
, RROutput id
)
40 m_proposedRotation
= m_originalRotation
;
41 m_proposedRate
= m_originalRate
;
42 m_proposedRect
= m_originalRect
;
45 RandROutput::~RandROutput()
49 RROutput
RandROutput::id() const
54 RandRScreen
*RandROutput::screen() const
59 bool RandROutput::queryOutputInfo(void)
61 XRROutputInfo
*info
= XRRGetOutputInfo(QX11Info::display(), m_screen
->resources(), m_id
);
65 if (RandR::timestamp
!= info
->timestamp
) {
66 RandR::timestamp
= info
->timestamp
;
70 // Set up the output's connection status, name, and current
72 bool pConn
= m_connected
;
73 m_connected
= (info
->connection
== RR_Connected
);
74 if (pConn
!= m_connected
) {
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?
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
94 for (int i
= 0; i
< m_possibleCrtcs
.count(); ++i
)
96 RandRCrtc
*crtc
= m_screen
->crtc(m_possibleCrtcs
.at(i
));
98 m_rotations
|= crtc
->rotations();
100 m_originalRotation
= m_crtc
->rotation();
101 m_originalRate
= m_crtc
->refreshRate();
102 m_originalRect
= m_crtc
->rect();
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
);
116 void RandROutput::loadSettings(bool notify
)
121 qDebug() << "STUB: calling queryOutputInfo instead. Check if this has "
122 << "any undesired effects. ";
125 void RandROutput::handleEvent(XRROutputChangeNotifyEvent
*event
)
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...
137 //qWarning() << "FIXME: Output event ignored!";
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
);
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:
177 // - TV output formats
179 char *name
= XGetAtomName(QX11Info::display(), event
->property
);
180 qDebug() << "Got XRROutputPropertyNotifyEvent for property Atom " << name
;
184 QString
RandROutput::name() const
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
218 ModeList
RandROutput::modes() const
223 RandRMode
RandROutput::mode() const
231 return m_crtc
->mode();
234 RandRMode
RandROutput::preferredMode(void) const
236 return m_preferredMode
;
239 SizeList
RandROutput::sizes() const
243 foreach(const RRMode
& m
, m_modes
)
245 RandRMode mode
= m_screen
->mode(m
);
248 if (sizeList
.indexOf(mode
.size()) == -1)
249 sizeList
.append(mode
.size());
254 QRect
RandROutput::rect() const
256 if (!m_crtc
) qDebug() << "No Crtc for output" << m_id
;
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
269 size
= rect().size();
271 foreach(const RRMode
& m
, m_modes
)
273 RandRMode mode
= m_screen
->mode(m
);
276 if (mode
.size() == size
)
277 list
.append(mode
.refreshRate());
282 float RandROutput::refreshRate() const
284 return m_crtc
->mode().refreshRate();
287 int RandROutput::rotations() const
292 int RandROutput::rotation() const
295 return RandR::Rotate0
;
298 return m_crtc
->rotation();
301 bool RandROutput::isConnected() const
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();
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()
345 qDebug() << "Attempting to enable " << m_name
;
346 RandRCrtc
*crtc
= findEmptyCrtc();
352 RandRCrtc
*RandROutput::findEmptyCrtc()
356 foreach(const RRCrtc
& c
, m_possibleCrtcs
)
358 crtc
= m_screen
->crtc(c
);
359 if (crtc
->connectedOutputs().count() == 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())
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())
389 // revert changes if we didn't succeed
390 crtc
->proposeOriginal();
391 crtc
->applyProposed();
393 // switch back to the old crtc
398 bool RandROutput::setCrtc(RandRCrtc
*crtc
, bool applyNow
)
401 if( !crtc
|| (m_crtc
&& crtc
->id() == m_crtc
->id()) )
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();
414 if (!m_crtc
->isValid())
417 if (!m_crtc
->addOutput(m_id
)) {
421 qDebug() << "CRTC outputs:" << m_crtc
->connectedOutputs();
422 connect(m_crtc
, SIGNAL(crtcChanged(RRCrtc
, int)),
423 this, SLOT(slotCrtcChanged(RRCrtc
, int)));
428 void RandROutput::slotCrtcChanged(RRCrtc c
, int changes
)
432 //FIXME select which changes we should notify
433 emit
outputChanged(m_id
, changes
);
436 bool RandROutput::applyProposed(int changes
)
442 if (changes
& RandR::ChangeRect
)
446 // first try to apply to the already attached crtc if any
447 if (m_crtc
->isValid())
450 if (tryCrtc(crtc
, changes
))
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
465 // try the crtc, and if no confirmation is needed or the user confirm, save the new settings
466 if (tryCrtc(crtc
, changes
))