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

« back to all changes in this revision

Viewing changes to kcontrol/randr/randrcrtc.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
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 */
 
18
 
 
19
#include "randrcrtc.h"
 
20
#include "randrscreen.h"
 
21
#include "randroutput.h"
 
22
#include "randrmode.h"
 
23
 
 
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)
 
29
{
 
30
        m_screen = parent;
 
31
        Q_ASSERT(m_screen);
 
32
 
 
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;
 
37
        
 
38
        m_id = id;
 
39
}
 
40
 
 
41
RandRCrtc::~RandRCrtc()
 
42
{
 
43
        // do nothing for now
 
44
}
 
45
 
 
46
RRCrtc RandRCrtc::id() const
 
47
{
 
48
        return m_id;
 
49
}
 
50
 
 
51
int RandRCrtc::rotations() const
 
52
{
 
53
        return m_rotations;
 
54
}
 
55
 
 
56
int RandRCrtc::rotation() const
 
57
{
 
58
        return m_currentRotation;
 
59
}
 
60
 
 
61
bool RandRCrtc::isValid(void) const
 
62
{
 
63
        return m_id != None;
 
64
}
 
65
 
 
66
void RandRCrtc::loadSettings(bool notify)
 
67
{
 
68
        if(m_id == None)
 
69
                return;
 
70
        
 
71
        kDebug() << "Querying information about CRTC" << m_id;
 
72
        
 
73
        int changes = 0;
 
74
        XRRCrtcInfo *info = XRRGetCrtcInfo(QX11Info::display(), m_screen->resources(), m_id);
 
75
        Q_ASSERT(info);
 
76
 
 
77
        if (RandR::timestamp != info->timestamp)
 
78
                RandR::timestamp = info->timestamp;
 
79
 
 
80
        QRect rect = QRect(info->x, info->y, info->width, info->height);
 
81
        if (rect != m_currentRect)
 
82
        {
 
83
                m_currentRect = rect;
 
84
                changes |= RandR::ChangeRect;
 
85
        }
 
86
 
 
87
        // get all connected outputs 
 
88
        // and create a list of modes that are available in all connected outputs
 
89
        OutputList outputs;
 
90
 
 
91
        for (int i = 0; i < info->noutput; ++i) {
 
92
                outputs.append(info->outputs[i]);
 
93
        }
 
94
 
 
95
        // check if the list changed from the original one
 
96
        if (outputs != m_connectedOutputs)
 
97
        {
 
98
                changes |= RandR::ChangeOutputs;
 
99
                m_connectedOutputs = outputs;   
 
100
        }
 
101
        
 
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]);
 
106
 
 
107
        if (outputs != m_possibleOutputs)
 
108
        {
 
109
                changes |= RandR::ChangeOutputs;
 
110
                m_possibleOutputs = outputs;
 
111
        }
 
112
 
 
113
        // get all rotations
 
114
        m_rotations = info->rotations;
 
115
        if (m_currentRotation != info->rotation)
 
116
        {
 
117
                m_currentRotation = info->rotation;
 
118
                changes |= RandR::ChangeRotation;
 
119
        }
 
120
 
 
121
        // check if the current mode has changed
 
122
        if (m_currentMode != info->mode)
 
123
        {
 
124
                m_currentMode = info->mode;
 
125
                changes |= RandR::ChangeMode;
 
126
        }
 
127
 
 
128
        RandRMode m = m_screen->mode(m_currentMode);
 
129
        if (m_currentRate != m.refreshRate())
 
130
        {
 
131
                m_currentRate = m.refreshRate();
 
132
                changes |= RandR::ChangeRate;
 
133
        }
 
134
 
 
135
        // just to make sure it gets initialized
 
136
        m_proposedRect = m_currentRect;
 
137
        m_proposedRotation = m_currentRotation;
 
138
        m_proposedRate = m_currentRate;
 
139
                
 
140
        // free the info
 
141
        XRRFreeCrtcInfo(info);
 
142
 
 
143
        if (changes && notify)
 
144
                emit crtcChanged(m_id, changes);
 
145
}
 
146
 
 
147
void RandRCrtc::handleEvent(XRRCrtcChangeNotifyEvent *event)
 
148
{
 
149
        kDebug() << "[CRTC] Event...";
 
150
        int changed = 0;
 
151
 
 
152
        if (event->mode != m_currentMode)
 
153
        {
 
154
                kDebug() << "   Changed mode";
 
155
                changed |= RandR::ChangeMode;
 
156
                m_currentMode = event->mode;
 
157
        }
 
158
        
 
159
        if (event->rotation != m_currentRotation)
 
160
        {
 
161
                kDebug() << "   Changed rotation: " << event->rotation;
 
162
                changed |= RandR::ChangeRotation;
 
163
                m_currentRotation = event->rotation;
 
164
        }
 
165
        if (event->x != m_currentRect.x() || event->y != m_currentRect.y())
 
166
        {
 
167
                kDebug() << "   Changed position: " << event->x << "," << event->y;
 
168
                changed |= RandR::ChangeRect;
 
169
                m_currentRect.moveTopLeft(QPoint(event->x, event->y));
 
170
        }
 
171
 
 
172
        RandRMode mode = m_screen->mode(m_currentMode);
 
173
        if (mode.size() != m_currentRect.size())
 
174
        {
 
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
 
179
        }
 
180
 
 
181
        if (changed)
 
182
                emit crtcChanged(m_id, changed);
 
183
}
 
184
 
 
185
RandRMode RandRCrtc::mode() const
 
186
{
 
187
        return m_screen->mode(m_currentMode);
 
188
}
 
189
 
 
190
QRect RandRCrtc::rect() const
 
191
{
 
192
        return m_currentRect;
 
193
}
 
194
 
 
195
float RandRCrtc::refreshRate() const
 
196
{
 
197
        return m_currentRate;
 
198
}
 
199
 
 
200
bool RandRCrtc::applyProposed()
 
201
{
 
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();
 
214
 
 
215
        RandRMode mode;
 
216
        if (m_proposedRect.size() == m_currentRect.size() && m_proposedRate == m_currentRate)
 
217
        {
 
218
                mode = m_screen->mode(m_currentMode);
 
219
        }
 
220
        else
 
221
        {
 
222
                // find a mode that has the desired size and is supported
 
223
                // by all connected outputs
 
224
                ModeList modeList = modes();
 
225
                ModeList matchModes;
 
226
 
 
227
                foreach(RRMode m, modeList)
 
228
                {
 
229
                        RandRMode mode = m_screen->mode(m);
 
230
                        if (mode.size() == m_proposedRect.size())
 
231
                                matchModes.append(m);
 
232
                }
 
233
 
 
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());
 
242
 
 
243
                foreach(RRMode m, matchModes)
 
244
                {
 
245
                        RandRMode testMode = m_screen->mode(m);
 
246
                        if (testMode.refreshRate() == m_proposedRate)
 
247
                        {
 
248
                                mode = testMode;
 
249
                                break;
 
250
                        }
 
251
                }
 
252
        }
 
253
        
 
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;
 
259
 
 
260
        if (mode.isValid())
 
261
        {
 
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))
 
267
                {
 
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;
 
271
 
 
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))
 
275
                        {
 
276
                                // try to adjust the screen size
 
277
                                if (!m_screen->adjustSize(r))
 
278
                                        return false;
 
279
                        }
 
280
 
 
281
                }
 
282
                else
 
283
                {
 
284
 
 
285
                        QRect r(m_proposedRect.topLeft(), QSize(m_proposedRect.height(), m_proposedRect.width()));
 
286
                        if (!m_screen->rect().contains(r))
 
287
                        {
 
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;
 
292
                                
 
293
                                // adjust the screen size
 
294
                                r = r.united(m_currentRect);
 
295
                                if (!m_screen->adjustSize(r))
 
296
                                        return false;
 
297
                        }
 
298
                }
 
299
        }
 
300
        
 
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);
 
304
        
 
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()); 
 
308
        
 
309
        delete[] outputs;
 
310
        
 
311
        bool ret;
 
312
        if (s == RRSetConfigSuccess)
 
313
        {
 
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;
 
321
        }
 
322
        else
 
323
        {
 
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);
 
329
        }
 
330
 
 
331
        m_screen->adjustSize();
 
332
        return ret;
 
333
}
 
334
 
 
335
bool RandRCrtc::proposeSize(const QSize &s)
 
336
{
 
337
        m_proposedRect.setSize(s);
 
338
        m_proposedRate = 0;
 
339
        return true;
 
340
}
 
341
 
 
342
bool RandRCrtc::proposePosition(const QPoint &p)
 
343
{
 
344
        m_proposedRect.moveTopLeft(p);
 
345
        return true;
 
346
}
 
347
 
 
348
bool RandRCrtc::proposeRotation(int rotation)
 
349
{
 
350
        // check if this crtc supports the asked rotation
 
351
        if (!rotation & m_rotations)
 
352
                return false;
 
353
 
 
354
        m_proposedRotation = rotation;
 
355
        return true;
 
356
 
 
357
}
 
358
 
 
359
bool RandRCrtc::proposeRefreshRate(float rate)
 
360
{
 
361
        m_proposedRate = rate;
 
362
        return true;
 
363
}
 
364
 
 
365
void RandRCrtc::proposeOriginal()
 
366
{
 
367
        m_proposedRotation = m_originalRotation;
 
368
        m_proposedRect = m_originalRect;
 
369
        m_proposedRate = m_originalRate;
 
370
}
 
371
 
 
372
void RandRCrtc::setOriginal()
 
373
{
 
374
        m_originalRotation = m_currentRotation;
 
375
        m_originalRect = m_currentRect;
 
376
        m_originalRate = m_currentRate;
 
377
}
 
378
 
 
379
bool RandRCrtc::proposedChanged()
 
380
{
 
381
        return (m_proposedRotation != m_currentRotation ||
 
382
                m_proposedRect != m_currentRect ||
 
383
                m_proposedRate != m_currentRate);
 
384
}
 
385
 
 
386
bool RandRCrtc::addOutput(RROutput output, const QSize &s)
 
387
{
 
388
        QSize size = s;
 
389
        // if no mode was given, use the current one
 
390
        if (!size.isValid())
 
391
                size = m_currentRect.size();
 
392
 
 
393
        // check if this output is not already on this crtc
 
394
        // if not, add it
 
395
        if (m_connectedOutputs.indexOf(output) == -1)
 
396
        {
 
397
                // the given output is not possible
 
398
                if (m_possibleOutputs.indexOf(output) == -1)
 
399
                        return false;
 
400
 
 
401
                m_connectedOutputs.append(output);
 
402
        }
 
403
        m_proposedRect = QRect(m_proposedRect.topLeft(), s);
 
404
        return true;
 
405
}
 
406
 
 
407
bool RandRCrtc::removeOutput(RROutput output)
 
408
{
 
409
        int index = m_connectedOutputs.indexOf(output);
 
410
        if (index == -1)
 
411
                return false;
 
412
 
 
413
        m_connectedOutputs.removeAt(index);
 
414
        return true;
 
415
}       
 
416
 
 
417
OutputList RandRCrtc::connectedOutputs() const
 
418
{
 
419
        return m_connectedOutputs;
 
420
}
 
421
 
 
422
ModeList RandRCrtc::modes() const
 
423
{       
 
424
        ModeList modeList;
 
425
 
 
426
        bool first = true;
 
427
 
 
428
        foreach(RROutput o, m_connectedOutputs)
 
429
        {
 
430
                RandROutput *output = m_screen->output(o);
 
431
                if (first)
 
432
                {
 
433
                        modeList = output->modes();
 
434
                        first = false;
 
435
                }
 
436
                else
 
437
                {
 
438
                        foreach(RRMode m, modeList)
 
439
                        {
 
440
                                if (output->modes().indexOf(m) == -1)
 
441
                                        modeList.removeAll(m);
 
442
                        }
 
443
                }
 
444
        }
 
445
 
 
446
        return modeList;
 
447
}
 
448
 
 
449
#include "randrcrtc.moc"
 
450
 
 
451