~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to libs/kephal/service/xrandr12/randroutput.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
9
 *
 
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.
 
14
 *
 
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.
 
18
 */
 
19
 
 
20
#include "randroutput.h"
 
21
 
 
22
#include <QX11Info>
 
23
#include <KDebug>
 
24
 
 
25
#include "randrscreen.h"
 
26
#include "randrcrtc.h"
 
27
#include "randrmode.h"
 
28
 
 
29
 
 
30
 
 
31
RandROutput::RandROutput(RandRScreen *parent, RROutput id)
 
32
: QObject(parent)
 
33
{
 
34
    m_screen = parent;
 
35
    Q_ASSERT(m_screen);
 
36
 
 
37
    m_id = id;
 
38
    m_crtc = 0;
 
39
    m_rotations = 0;
 
40
    m_connected = false;
 
41
 
 
42
    queryOutputInfo();
 
43
 
 
44
    m_proposedRotation = m_originalRotation;
 
45
    m_proposedRate = m_originalRate;
 
46
    m_proposedRect = m_originalRect;
 
47
}
 
48
 
 
49
RandROutput::~RandROutput()
 
50
{
 
51
}
 
52
 
 
53
RROutput RandROutput::id() const
 
54
{
 
55
    return m_id;
 
56
}
 
57
 
 
58
RandRScreen *RandROutput::screen() const
 
59
{
 
60
    return m_screen;
 
61
}
 
62
 
 
63
bool RandROutput::queryOutputInfo(void)
 
64
{
 
65
    XRROutputInfo *info = XRRGetOutputInfo(QX11Info::display(), m_screen->resources(), m_id);
 
66
    Q_ASSERT(info);
 
67
 
 
68
        bool changes = false;
 
69
    if (RandR::timestamp != info->timestamp) {
 
70
        RandR::timestamp = info->timestamp;
 
71
                //changes = true;
 
72
        }
 
73
 
 
74
    // Set up the output's connection status, name, and current
 
75
    // CRT controller.
 
76
        bool pConn = m_connected;
 
77
    m_connected = (info->connection == RR_Connected);
 
78
        if (pConn != m_connected) {
 
79
            changes = true;
 
80
        }
 
81
    m_name = info->name;
 
82
 
 
83
    setCrtc(m_screen->crtc(info->crtc));
 
84
    m_crtc->loadSettings(false);
 
85
 
 
86
    for(int i = 0; i < info->ncrtc; ++i)
 
87
        m_possibleCrtcs.append(info->crtcs[i]);
 
88
 
 
89
    //TODO: is it worth notifying changes on mode list changing?
 
90
    m_modes.clear();
 
91
    m_preferredMode = m_screen->mode(info->modes[info->npreferred]);
 
92
 
 
93
    for (int i = 0; i < info->nmode; ++i)
 
94
        m_modes.append(info->modes[i]);
 
95
 
 
96
    //get all possible rotations
 
97
    m_rotations = 0;
 
98
    for (int i = 0; i < m_possibleCrtcs.count(); ++i)
 
99
    {
 
100
        RandRCrtc *crtc = m_screen->crtc(m_possibleCrtcs.at(i));
 
101
        Q_ASSERT(crtc);
 
102
        m_rotations |= crtc->rotations();
 
103
    }
 
104
    m_originalRotation = m_crtc->rotation();
 
105
    m_originalRate     = m_crtc->refreshRate();
 
106
    m_originalRect     = m_crtc->rect();
 
107
 
 
108
    if(isConnected()) {
 
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;
 
113
    }
 
114
 
 
115
    XRRFreeOutputInfo(info);
 
116
 
 
117
    return changes;
 
118
}
 
119
 
 
120
void RandROutput::loadSettings(bool notify)
 
121
{
 
122
    Q_UNUSED(notify);
 
123
    queryOutputInfo();
 
124
 
 
125
    kDebug() << "STUB: calling queryOutputInfo instead. Check if this has "
 
126
             << "any undesired effects. ";
 
127
}
 
128
 
 
129
void RandROutput::handleEvent(XRROutputChangeNotifyEvent *event)
 
130
{
 
131
    int changed = 0;
 
132
 
 
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;
 
138
 
 
139
    //FIXME: handling these events incorrectly, causing an X11 I/O error...
 
140
    // Disable for now.
 
141
    //qWarning() << "FIXME: Output event ignored!";
 
142
    //return;
 
143
 
 
144
    RRCrtc currentCrtc = m_crtc->id();
 
145
    if (event->crtc != currentCrtc)
 
146
    {
 
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);
 
155
    }
 
156
 
 
157
    if (event->mode != mode().id())
 
158
        changed |= RandR::ChangeMode;
 
159
 
 
160
    if (event->rotation != rotation())
 
161
        changed |= RandR::ChangeRotation;
 
162
 
 
163
    if((event->connection == RR_Connected) != m_connected)
 
164
    {
 
165
        changed |= RandR::ChangeConnection;
 
166
        m_connected = (event->connection == RR_Connected);
 
167
        if (!m_connected && currentCrtc != None)
 
168
            m_crtc = m_screen->crtc(None);
 
169
    }
 
170
 
 
171
    if(changed)
 
172
        emit outputChanged(m_id, changed);
 
173
}
 
174
 
 
175
void RandROutput::handlePropertyEvent(XRROutputPropertyNotifyEvent *event)
 
176
{
 
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:
 
180
    // - LVDS Backlights
 
181
    // - TV output formats
 
182
 
 
183
    char *name = XGetAtomName(QX11Info::display(), event->property);
 
184
    kDebug() << "Got XRROutputPropertyNotifyEvent for property Atom " << name;
 
185
    XFree(name);
 
186
}
 
187
 
 
188
QString RandROutput::name() const
 
189
{
 
190
    return m_name;
 
191
}
 
192
 
 
193
QString RandROutput::icon() const
 
194
{
 
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";
 
202
 
 
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";
 
208
 
 
209
    return "video-display";
 
210
}
 
211
 
 
212
CrtcList RandROutput::possibleCrtcs() const
 
213
{
 
214
    return m_possibleCrtcs;
 
215
}
 
216
 
 
217
RandRCrtc *RandROutput::crtc() const
 
218
{
 
219
    return m_crtc;
 
220
}
 
221
 
 
222
ModeList RandROutput::modes() const
 
223
{
 
224
    return m_modes;
 
225
}
 
226
 
 
227
RandRMode RandROutput::mode() const
 
228
{
 
229
    if (!isConnected())
 
230
        return None;
 
231
 
 
232
    if (!m_crtc)
 
233
        return RandRMode();
 
234
 
 
235
    return m_crtc->mode();
 
236
}
 
237
 
 
238
RandRMode RandROutput::preferredMode(void) const
 
239
{
 
240
    return m_preferredMode;
 
241
}
 
242
 
 
243
SizeList RandROutput::sizes() const
 
244
{
 
245
    SizeList sizeList;
 
246
 
 
247
    foreach(const RRMode & m, m_modes)
 
248
    {
 
249
        RandRMode mode = m_screen->mode(m);
 
250
        if (!mode.isValid())
 
251
            continue;
 
252
        if (sizeList.indexOf(mode.size()) == -1)
 
253
            sizeList.append(mode.size());
 
254
    }
 
255
    return sizeList;
 
256
}
 
257
 
 
258
QRect RandROutput::rect() const
 
259
{
 
260
    if (!m_crtc) kDebug() << "No Crtc for output" << m_id;
 
261
        Q_ASSERT(m_crtc);
 
262
    if (!m_crtc->isValid())
 
263
        return QRect(0, 0, 0, 0);
 
264
 
 
265
    return m_crtc->rect();
 
266
}
 
267
 
 
268
RateList RandROutput::refreshRates(const QSize &s) const
 
269
{
 
270
    RateList list;
 
271
    QSize size = s;
 
272
    if (!size.isValid())
 
273
        size = rect().size();
 
274
 
 
275
    foreach(const RRMode & m, m_modes)
 
276
    {
 
277
        RandRMode mode = m_screen->mode(m);
 
278
        if (!mode.isValid())
 
279
            continue;
 
280
        if (mode.size() == size)
 
281
            list.append(mode.refreshRate());
 
282
    }
 
283
    return list;
 
284
}
 
285
 
 
286
float RandROutput::refreshRate() const
 
287
{
 
288
    return m_crtc->mode().refreshRate();
 
289
}
 
290
 
 
291
int RandROutput::rotations() const
 
292
{
 
293
    return m_rotations;
 
294
}
 
295
 
 
296
int RandROutput::rotation() const
 
297
{
 
298
    if (!isActive())
 
299
        return RandR::Rotate0;
 
300
 
 
301
    Q_ASSERT(m_crtc);
 
302
    return m_crtc->rotation();
 
303
}
 
304
 
 
305
bool RandROutput::isConnected() const
 
306
{
 
307
    return m_connected;
 
308
}
 
309
 
 
310
bool RandROutput::isActive() const
 
311
{
 
312
    return (m_connected && mode().isValid() && m_crtc->id() != None);
 
313
}
 
314
 
 
315
void RandROutput::proposeOriginal()
 
316
{
 
317
    if (m_crtc->id() != None)
 
318
        m_crtc->proposeOriginal();
 
319
}
 
320
 
 
321
void RandROutput::proposeRefreshRate(float rate)
 
322
{
 
323
    m_originalRate = refreshRate();
 
324
    m_proposedRate = rate;
 
325
}
 
326
 
 
327
void RandROutput::proposeRect(const QRect &r)
 
328
{
 
329
    m_originalRect = rect();
 
330
    m_proposedRect = r;
 
331
}
 
332
 
 
333
void RandROutput::proposeRotation(int r)
 
334
{
 
335
    m_originalRotation = rotation();
 
336
    m_proposedRotation = r;
 
337
}
 
338
 
 
339
void RandROutput::slotDisable()
 
340
{
 
341
    setCrtc(m_screen->crtc(None));
 
342
}
 
343
 
 
344
void RandROutput::slotEnable()
 
345
{
 
346
    if(!m_connected)
 
347
        return;
 
348
 
 
349
    kDebug() << "Attempting to enable " << m_name;
 
350
    RandRCrtc *crtc = findEmptyCrtc();
 
351
 
 
352
    if(crtc)
 
353
        setCrtc(crtc);
 
354
}
 
355
 
 
356
RandRCrtc *RandROutput::findEmptyCrtc()
 
357
{
 
358
    RandRCrtc *crtc = 0;
 
359
 
 
360
    foreach(const RRCrtc & c, m_possibleCrtcs)
 
361
    {
 
362
        crtc = m_screen->crtc(c);
 
363
        if (crtc->connectedOutputs().count() == 0)
 
364
            return crtc;
 
365
    }
 
366
 
 
367
    return 0;
 
368
}
 
369
 
 
370
bool RandROutput::tryCrtc(RandRCrtc *crtc, int changes)
 
371
{
 
372
    RandRCrtc *oldCrtc = m_crtc;
 
373
 
 
374
    // if we are not yet using this crtc, switch to use it
 
375
    if (crtc->id() != oldCrtc->id())
 
376
        setCrtc(crtc);
 
377
 
 
378
    crtc->setOriginal();
 
379
 
 
380
    if (changes & RandR::ChangeRect)
 
381
    {
 
382
        crtc->proposeSize(m_proposedRect.size());
 
383
        crtc->proposePosition(m_proposedRect.topLeft());
 
384
    }
 
385
    if (changes & RandR::ChangeRotation)
 
386
        crtc->proposeRotation(m_proposedRotation);
 
387
    if (changes & RandR::ChangeRate)
 
388
        crtc->proposeRefreshRate(m_proposedRate);
 
389
 
 
390
    if (crtc->applyProposed())
 
391
        return true;
 
392
 
 
393
    // revert changes if we didn't succeed
 
394
    crtc->proposeOriginal();
 
395
    crtc->applyProposed();
 
396
 
 
397
    // switch back to the old crtc
 
398
    setCrtc(oldCrtc);
 
399
    return false;
 
400
}
 
401
 
 
402
bool RandROutput::setCrtc(RandRCrtc *crtc, bool applyNow)
 
403
{
 
404
    Q_UNUSED(applyNow);
 
405
    if( !crtc || (m_crtc && crtc->id() == m_crtc->id()) )
 
406
        return false;
 
407
 
 
408
    kDebug() << "Setting CRTC" << crtc->id() << "on output" << m_name << "(previous" << (m_crtc ? m_crtc->id() : 0) << ")";
 
409
 
 
410
    if(m_crtc && m_crtc->isValid()) {
 
411
        disconnect(m_crtc, SIGNAL(crtcChanged(RRCrtc, int)),
 
412
                   this, SLOT(slotCrtcChanged(RRCrtc, int)));
 
413
 
 
414
        m_crtc->removeOutput(m_id);
 
415
//         m_crtc->applyProposed();
 
416
    }
 
417
    m_crtc = crtc;
 
418
    if (!m_crtc->isValid())
 
419
        return false;
 
420
 
 
421
    if (!m_crtc->addOutput(m_id)) {
 
422
        return false;
 
423
    }
 
424
 
 
425
    kDebug() << "CRTC outputs:" << m_crtc->connectedOutputs();
 
426
    connect(m_crtc, SIGNAL(crtcChanged(RRCrtc, int)),
 
427
            this, SLOT(slotCrtcChanged(RRCrtc, int)));
 
428
 
 
429
    return true;
 
430
}
 
431
 
 
432
void RandROutput::slotCrtcChanged(RRCrtc c, int changes)
 
433
{
 
434
    Q_UNUSED(c);
 
435
 
 
436
    //FIXME select which changes we should notify
 
437
    emit outputChanged(m_id, changes);
 
438
}
 
439
 
 
440
bool RandROutput::applyProposed(int changes)
 
441
{
 
442
    RandRCrtc *crtc;
 
443
 
 
444
    QRect r;
 
445
 
 
446
    if (changes & RandR::ChangeRect)
 
447
        r = m_proposedRect;
 
448
 
 
449
 
 
450
    // first try to apply to the already attached crtc if any
 
451
    if (m_crtc->isValid())
 
452
    {
 
453
        crtc = m_crtc;
 
454
        if (tryCrtc(crtc, changes))
 
455
        {
 
456
            return true;
 
457
        }
 
458
        return false;
 
459
    }
 
460
 
 
461
    //then try an empty crtc
 
462
    crtc = findEmptyCrtc();
 
463
 
 
464
    // TODO: check if we can add this output to a CRTC which already has an output
 
465
    // connection
 
466
    if (!crtc)
 
467
        return false;
 
468
 
 
469
    // try the crtc, and if no confirmation is needed or the user confirm, save the new settings
 
470
    if (tryCrtc(crtc, changes))
 
471
    {
 
472
        return true;
 
473
    }
 
474
 
 
475
    return false;
 
476
}
 
477