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"
25
#include "randrscreen.h"
26
#include "randrcrtc.h"
27
#include "randrmode.h"
31
RandROutput::RandROutput(RandRScreen *parent, RROutput id)
44
m_proposedRotation = m_originalRotation;
45
m_proposedRate = m_originalRate;
46
m_proposedRect = m_originalRect;
49
RandROutput::~RandROutput()
53
RROutput RandROutput::id() const
58
RandRScreen *RandROutput::screen() const
63
bool RandROutput::queryOutputInfo(void)
65
XRROutputInfo *info = XRRGetOutputInfo(QX11Info::display(), m_screen->resources(), m_id);
69
if (RandR::timestamp != info->timestamp) {
70
RandR::timestamp = info->timestamp;
74
// Set up the output's connection status, name, and current
76
bool pConn = m_connected;
77
m_connected = (info->connection == RR_Connected);
78
if (pConn != m_connected) {
83
setCrtc(m_screen->crtc(info->crtc));
84
m_crtc->loadSettings(false);
86
for(int i = 0; i < info->ncrtc; ++i)
87
m_possibleCrtcs.append(info->crtcs[i]);
89
//TODO: is it worth notifying changes on mode list changing?
91
m_preferredMode = m_screen->mode(info->modes[info->npreferred]);
93
for (int i = 0; i < info->nmode; ++i)
94
m_modes.append(info->modes[i]);
96
//get all possible rotations
98
for (int i = 0; i < m_possibleCrtcs.count(); ++i)
100
RandRCrtc *crtc = m_screen->crtc(m_possibleCrtcs.at(i));
102
m_rotations |= crtc->rotations();
104
m_originalRotation = m_crtc->rotation();
105
m_originalRate = m_crtc->refreshRate();
106
m_originalRect = m_crtc->rect();
109
kDebug() << "Output name:" << m_name;
110
kDebug() << "Output refresh rate:" << m_originalRate;
111
kDebug() << "Output rect:" << m_originalRect;
112
kDebug() << "Output rotation:" << m_originalRotation;
115
XRRFreeOutputInfo(info);
120
void RandROutput::loadSettings(bool notify)
125
kDebug() << "STUB: calling queryOutputInfo instead. Check if this has "
126
<< "any undesired effects. ";
129
void RandROutput::handleEvent(XRROutputChangeNotifyEvent *event)
133
kDebug() << "[OUTPUT" << m_id << "] Got event for " << m_name;
134
kDebug() << " crtc: " << event->crtc << "(current " << m_crtc->id() << ")";
135
kDebug() << " mode: " << event->mode << "(current " << mode().id() << ")";
136
kDebug() << " rotation: " << event->rotation;
137
kDebug() << " connection: " << event->connection;
139
//FIXME: handling these events incorrectly, causing an X11 I/O error...
141
//qWarning() << "FIXME: Output event ignored!";
144
RRCrtc currentCrtc = m_crtc->id();
145
if (event->crtc != currentCrtc)
147
changed |= RandR::ChangeCrtc;
148
// update crtc settings
149
if (currentCrtc != None)
150
m_crtc->loadSettings(true);
151
//m_screen->crtc(m_currentCrtc)->loadSettings(true);
152
setCrtc(m_screen->crtc(event->crtc));
153
if (currentCrtc != None)
154
m_crtc->loadSettings(true);
157
if (event->mode != mode().id())
158
changed |= RandR::ChangeMode;
160
if (event->rotation != rotation())
161
changed |= RandR::ChangeRotation;
163
if((event->connection == RR_Connected) != m_connected)
165
changed |= RandR::ChangeConnection;
166
m_connected = (event->connection == RR_Connected);
167
if (!m_connected && currentCrtc != None)
168
m_crtc = m_screen->crtc(None);
172
emit outputChanged(m_id, changed);
175
void RandROutput::handlePropertyEvent(XRROutputPropertyNotifyEvent *event)
177
// TODO: Do something with this!
178
// By perusing thru some XOrg drivers, some of the properties that can
179
// are configured through XRANDR are:
181
// - TV output formats
183
char *name = XGetAtomName(QX11Info::display(), event->property);
184
kDebug() << "Got XRROutputPropertyNotifyEvent for property Atom " << name;
188
QString RandROutput::name() const
193
QString RandROutput::icon() const
195
// FIXME: check what names we should use and what kind of outputs randr can
196
// report. It would also be interesting to be able to get the monitor name
197
// using EDID or something like that, just don't know if it is even possible.
198
if (m_name.contains("VGA"))
199
return "video-display";
200
else if (m_name.contains("LVDS"))
201
return "video-display";
203
// I doubt this is a good choice; can't find anything better in the spec.
204
// video-x-generic might work, but that's a mimetype, which is inappropriate
205
// for an output connection type.
206
else if (m_name.contains("TV"))
207
return "multimedia-player";
209
return "video-display";
212
CrtcList RandROutput::possibleCrtcs() const
214
return m_possibleCrtcs;
217
RandRCrtc *RandROutput::crtc() const
222
ModeList RandROutput::modes() const
227
RandRMode RandROutput::mode() const
235
return m_crtc->mode();
238
RandRMode RandROutput::preferredMode(void) const
240
return m_preferredMode;
243
SizeList RandROutput::sizes() const
247
foreach(const RRMode & m, m_modes)
249
RandRMode mode = m_screen->mode(m);
252
if (sizeList.indexOf(mode.size()) == -1)
253
sizeList.append(mode.size());
258
QRect RandROutput::rect() const
260
if (!m_crtc) kDebug() << "No Crtc for output" << m_id;
262
if (!m_crtc->isValid())
263
return QRect(0, 0, 0, 0);
265
return m_crtc->rect();
268
RateList RandROutput::refreshRates(const QSize &s) const
273
size = rect().size();
275
foreach(const RRMode & m, m_modes)
277
RandRMode mode = m_screen->mode(m);
280
if (mode.size() == size)
281
list.append(mode.refreshRate());
286
float RandROutput::refreshRate() const
288
return m_crtc->mode().refreshRate();
291
int RandROutput::rotations() const
296
int RandROutput::rotation() const
299
return RandR::Rotate0;
302
return m_crtc->rotation();
305
bool RandROutput::isConnected() const
310
bool RandROutput::isActive() const
312
return (m_connected && mode().isValid() && m_crtc->id() != None);
315
void RandROutput::proposeOriginal()
317
if (m_crtc->id() != None)
318
m_crtc->proposeOriginal();
321
void RandROutput::proposeRefreshRate(float rate)
323
m_originalRate = refreshRate();
324
m_proposedRate = rate;
327
void RandROutput::proposeRect(const QRect &r)
329
m_originalRect = rect();
333
void RandROutput::proposeRotation(int r)
335
m_originalRotation = rotation();
336
m_proposedRotation = r;
339
void RandROutput::slotDisable()
341
setCrtc(m_screen->crtc(None));
344
void RandROutput::slotEnable()
349
kDebug() << "Attempting to enable " << m_name;
350
RandRCrtc *crtc = findEmptyCrtc();
356
RandRCrtc *RandROutput::findEmptyCrtc()
360
foreach(const RRCrtc & c, m_possibleCrtcs)
362
crtc = m_screen->crtc(c);
363
if (crtc->connectedOutputs().count() == 0)
370
bool RandROutput::tryCrtc(RandRCrtc *crtc, int changes)
372
RandRCrtc *oldCrtc = m_crtc;
374
// if we are not yet using this crtc, switch to use it
375
if (crtc->id() != oldCrtc->id())
380
if (changes & RandR::ChangeRect)
382
crtc->proposeSize(m_proposedRect.size());
383
crtc->proposePosition(m_proposedRect.topLeft());
385
if (changes & RandR::ChangeRotation)
386
crtc->proposeRotation(m_proposedRotation);
387
if (changes & RandR::ChangeRate)
388
crtc->proposeRefreshRate(m_proposedRate);
390
if (crtc->applyProposed())
393
// revert changes if we didn't succeed
394
crtc->proposeOriginal();
395
crtc->applyProposed();
397
// switch back to the old crtc
402
bool RandROutput::setCrtc(RandRCrtc *crtc, bool applyNow)
405
if( !crtc || (m_crtc && crtc->id() == m_crtc->id()) )
408
kDebug() << "Setting CRTC" << crtc->id() << "on output" << m_name << "(previous" << (m_crtc ? m_crtc->id() : 0) << ")";
410
if(m_crtc && m_crtc->isValid()) {
411
disconnect(m_crtc, SIGNAL(crtcChanged(RRCrtc, int)),
412
this, SLOT(slotCrtcChanged(RRCrtc, int)));
414
m_crtc->removeOutput(m_id);
415
// m_crtc->applyProposed();
418
if (!m_crtc->isValid())
421
if (!m_crtc->addOutput(m_id)) {
425
kDebug() << "CRTC outputs:" << m_crtc->connectedOutputs();
426
connect(m_crtc, SIGNAL(crtcChanged(RRCrtc, int)),
427
this, SLOT(slotCrtcChanged(RRCrtc, int)));
432
void RandROutput::slotCrtcChanged(RRCrtc c, int changes)
436
//FIXME select which changes we should notify
437
emit outputChanged(m_id, changes);
440
bool RandROutput::applyProposed(int changes)
446
if (changes & RandR::ChangeRect)
450
// first try to apply to the already attached crtc if any
451
if (m_crtc->isValid())
454
if (tryCrtc(crtc, changes))
461
//then try an empty crtc
462
crtc = findEmptyCrtc();
464
// TODO: check if we can add this output to a CRTC which already has an output
469
// try the crtc, and if no confirmation is needed or the user confirm, save the new settings
470
if (tryCrtc(crtc, changes))