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

« back to all changes in this revision

Viewing changes to kcontrol/randr/outputconfig.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 "outputconfig.h"
 
21
#include "outputgraphicsitem.h"
 
22
#include "randroutput.h"
 
23
#include "randrscreen.h"
 
24
#include "randrmode.h"
 
25
#include <kdebug.h>
 
26
 
 
27
OutputConfig::OutputConfig(QWidget *parent, RandROutput *output, OutputConfigList preceding)
 
28
        : QWidget(parent)
 
29
        , precedingOutputConfigs( preceding )
 
30
{
 
31
        m_output = output;
 
32
        Q_ASSERT(output);
 
33
 
 
34
        setupUi(this);
 
35
 
 
36
        // connect signals
 
37
        connect(positionCombo, SIGNAL(currentIndexChanged(int)),
 
38
                this, SLOT(positionComboChanged(int)));
 
39
        connect(sizeCombo, SIGNAL(currentIndexChanged(int)),
 
40
                this, SLOT(updateRateList(int)));
 
41
        connect(sizeCombo, SIGNAL(currentIndexChanged(int)),
 
42
                this, SLOT(updatePositionList()));
 
43
        connect(sizeCombo, SIGNAL(currentIndexChanged(int)),
 
44
                this, SLOT(updateRotationList()));
 
45
        connect(m_output, SIGNAL(outputChanged(RROutput, int)),
 
46
                this,     SLOT(outputChanged(RROutput, int)));
 
47
                  
 
48
        load();
 
49
 
 
50
        connect(sizeCombo,    SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
51
        connect(refreshCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
52
        connect(orientationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
53
        connect(positionCombo,    SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
54
        connect(positionOutputCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
55
        connect(sizeCombo,    SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateView()));
 
56
        connect(orientationCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateView()));
 
57
        connect(positionCombo,    SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateView()));
 
58
        connect(positionOutputCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(updateView()));
 
59
        connect(absolutePosX, SIGNAL(textChanged(const QString&)), this, SIGNAL(updateView()));
 
60
        connect(absolutePosY, SIGNAL(textChanged(const QString&)), this, SIGNAL(updateView()));
 
61
        // make sure to update option for relative position when other outputs get enabled/disabled
 
62
        foreach( OutputConfig* config, precedingOutputConfigs )
 
63
                connect( config, SIGNAL( updateView()), this, SLOT( updatePositionList()));
 
64
 
 
65
        updatePositionListTimer.setSingleShot( true );
 
66
        connect( &updatePositionListTimer, SIGNAL( timeout()), SLOT( updatePositionListDelayed()));
 
67
 
 
68
}
 
69
 
 
70
OutputConfig::~OutputConfig()
 
71
{
 
72
}
 
73
 
 
74
RandROutput *OutputConfig::output(void) const
 
75
{
 
76
        return m_output;
 
77
}
 
78
 
 
79
QPoint OutputConfig::position(void) const
 
80
{
 
81
        if( !isActive())
 
82
                return QPoint();
 
83
        int index = positionCombo->currentIndex();
 
84
        if((Relation)positionCombo->itemData(index).toInt() == Absolute)
 
85
                return QPoint(absolutePosX->text().toInt(), absolutePosY->text().toInt());
 
86
        
 
87
        foreach(OutputConfig *config, precedingOutputConfigs) {
 
88
                if( config->output()->id()
 
89
                        == positionOutputCombo->itemData( positionOutputCombo->currentIndex()).toUInt()) {
 
90
                        QPoint pos = config->position();
 
91
                        switch( (Relation)positionCombo->itemData(index).toInt()) {
 
92
                                case LeftOf:
 
93
                                        return QPoint( pos.x() - resolution().width(), pos.y());
 
94
                                case RightOf:
 
95
                                        return QPoint( pos.x() + config->resolution().width(), pos.y());
 
96
                                case Over:
 
97
                                        return QPoint( pos.x(), pos.y() - resolution().height());
 
98
                                case Under:
 
99
                                        return QPoint( pos.x(), pos.y() + config->resolution().height());
 
100
                                case SameAs:
 
101
                                        return pos;
 
102
                                default:
 
103
                                        abort();
 
104
                        }
 
105
                }
 
106
        }
 
107
        return QPoint(0, 0);
 
108
}
 
109
 
 
110
QSize OutputConfig::resolution(void) const
 
111
{
 
112
        if( sizeCombo->count() == 0 )
 
113
                return QSize();
 
114
        return sizeCombo->itemData(sizeCombo->currentIndex()).toSize();
 
115
}
 
116
 
 
117
QRect OutputConfig::rect() const
 
118
{
 
119
        return QRect( position(), resolution());
 
120
}
 
121
 
 
122
bool OutputConfig::isActive() const
 
123
{
 
124
        return sizeCombo->count() != 0 && !resolution().isEmpty();
 
125
}
 
126
 
 
127
float OutputConfig::refreshRate(void) const
 
128
{
 
129
        if( !isActive())
 
130
                return 0;
 
131
        float rate = float(refreshCombo->itemData(refreshCombo->currentIndex()).toDouble());
 
132
        if(rate == 0.0f) {
 
133
                RateList rates = m_output->refreshRates(resolution());
 
134
                return rates.first();
 
135
        }
 
136
        return rate;
 
137
}
 
138
 
 
139
int OutputConfig::rotation(void) const
 
140
{
 
141
        if( !isActive())
 
142
                return 0;
 
143
        return orientationCombo->itemData(orientationCombo->currentIndex()).toInt();
 
144
}
 
145
 
 
146
bool OutputConfig::hasPendingChanges( const QPoint& normalizePos ) const
 
147
{
 
148
        if (m_output->rect().translated( -normalizePos ) != QRect(position(), resolution())) {
 
149
                return true;
 
150
        }
 
151
        else if (m_output->rotation() != rotation()) {
 
152
                return true;
 
153
        }
 
154
        else if (m_output->refreshRate() != refreshRate()) {
 
155
                return true;
 
156
        }
 
157
        return false;
 
158
}
 
159
 
 
160
void OutputConfig::outputChanged(RROutput output, int changes)
 
161
{
 
162
        Q_ASSERT(m_output->id() == output); Q_UNUSED(output);
 
163
        kDebug() << "Output" << m_output->name() << "changed. ( mask =" << QString::number(changes) << ")";
 
164
        
 
165
        if(changes & RandR::ChangeOutputs) {
 
166
                kDebug() << "Outputs changed.";
 
167
        }
 
168
        
 
169
        if(changes & RandR::ChangeCrtc) {
 
170
                kDebug() << "Output CRTC changed.";
 
171
                
 
172
                updateSizeList();
 
173
                updateRateList();
 
174
                updateRotationList();
 
175
        }
 
176
        
 
177
        if(changes & RandR::ChangeRect) {
 
178
                QRect r = m_output->rect();
 
179
                kDebug() << "Output rect changed:" << r;
 
180
        }
 
181
        
 
182
        if(changes & RandR::ChangeRotation) {
 
183
                kDebug() << "Output rotation changed.";
 
184
                updateRotationList();
 
185
        }
 
186
        
 
187
        if(changes & RandR::ChangeConnection) {
 
188
                kDebug() << "Output connection status changed.";
 
189
                setEnabled(m_output->isConnected());
 
190
        }
 
191
        
 
192
        if(changes & RandR::ChangeRate) {
 
193
                kDebug() << "Output rate changed.";
 
194
                updateRateList();
 
195
        }
 
196
        
 
197
        if(changes & RandR::ChangeMode) {
 
198
                kDebug() << "Output mode changed.";
 
199
                updateSizeList();
 
200
                
 
201
                // This NEEDS to be fixed..
 
202
                //QSize modeSize = m_output->screen()->mode(m_output->mode()).size();
 
203
                QSize modeSize = m_output->mode().size();
 
204
                updateRateList(sizeCombo->findData(modeSize));
 
205
        }
 
206
}
 
207
 
 
208
QString OutputConfig::positionName(Relation position)
 
209
{
 
210
        switch(position) {
 
211
        case LeftOf:  return i18n("Left of");
 
212
        case RightOf: return i18n("Right of");
 
213
        case Over:    return i18nc("Output is placed above another one", "Above");
 
214
        case Under:   return i18nc("Output is placed below another one", "Below");
 
215
        case SameAs:  return i18n("Clone of");
 
216
        case Absolute:  return i18nc("Fixed, abitrary position", "Absolute");
 
217
        }
 
218
        
 
219
        return i18n("No relative position");
 
220
}
 
221
 
 
222
void OutputConfig::load()
 
223
{
 
224
        kDebug() << "Loading output configuration for" << m_output->name();
 
225
        setEnabled( m_output->isConnected() );
 
226
 
 
227
        orientationCombo->clear();
 
228
 
 
229
        if (!m_output->isConnected())
 
230
                return;
 
231
 
 
232
        /* Mode size configuration */
 
233
        updateSizeList();
 
234
        
 
235
        /* Output rotation and relative position */
 
236
        updateRotationList();
 
237
        updatePositionList();
 
238
        
 
239
        emit updateView();
 
240
}
 
241
 
 
242
void OutputConfig::setConfigDirty(void)
 
243
{
 
244
        m_changed = true;
 
245
        emit optionChanged();
 
246
}
 
247
 
 
248
bool OutputConfig::isRelativeTo( QRect rect, QRect to, Relation rel )
 
249
{
 
250
        switch( rel ) {
 
251
                case LeftOf:
 
252
                        return rect.x() + rect.width() == to.x() && rect.y() == to.y();
 
253
                case RightOf:
 
254
                        return rect.x() == to.x() + to.width() && rect.y() == to.y();
 
255
                case Over:
 
256
                        return rect.x() == to.x() && rect.y() + rect.height() == to.y();
 
257
                case Under:
 
258
                        return rect.x() == to.x() && rect.y() == to.y() + to.height();
 
259
                case SameAs:
 
260
                        return rect.topLeft() == to.topLeft();
 
261
                case Absolute:
 
262
                default:
 
263
                        return false;
 
264
        }
 
265
}
 
266
 
 
267
void OutputConfig::positionComboChanged(int item)
 
268
{
 
269
        Relation rel;
 
270
        rel = (Relation)positionCombo->itemData(item).toInt();
 
271
        
 
272
        bool isAbsolute = (rel == Absolute);
 
273
        
 
274
        positionOutputCombo->setVisible(!isAbsolute);
 
275
        absolutePosX->setVisible(isAbsolute);
 
276
        absolutePosY->setVisible(isAbsolute);
 
277
        
 
278
        if(isAbsolute) {
 
279
                int posX = m_output->rect().topLeft().x();
 
280
                int posY = m_output->rect().topLeft().y();
 
281
                
 
282
                absolutePosX->setText(QString::number(posX));
 
283
                absolutePosY->setText(QString::number(posY));
 
284
        }
 
285
}
 
286
 
 
287
void OutputConfig::updatePositionList(void)
 
288
{
 
289
        // Delay because
 
290
        // a) this is an optimization
 
291
        // b) this can be called in the middle of changing configuration and can
 
292
        //    lead to the comboboxes being setup to wrong values
 
293
        updatePositionListTimer.start( 0 );
 
294
}
 
295
 
 
296
void OutputConfig::updatePositionListDelayed()
 
297
{
 
298
        disconnect(positionCombo,    SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
299
        disconnect(positionOutputCombo,    SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
300
 
 
301
        bool enable = !resolution().isEmpty();
 
302
        positionCombo->setEnabled( enable );
 
303
        positionLabel->setEnabled( enable );
 
304
        positionOutputCombo->setEnabled( enable );
 
305
        absolutePosX->setEnabled( enable );
 
306
        absolutePosY->setEnabled( enable );
 
307
        // when updating, use previously set value, otherwise read it from the output
 
308
        QRect rect = positionCombo->count() > 0 ? QRect( position(), resolution()) : m_output->rect();
 
309
        positionCombo->clear();
 
310
        positionOutputCombo->clear();
 
311
 
 
312
        Relation rel = Absolute;
 
313
        // FIXME: get default value from KConfig
 
314
        for(int i = -1; i < 5; i++)
 
315
                positionCombo->addItem(OutputConfig::positionName((Relation)i), i);
 
316
        
 
317
        int index = positionCombo->findData((int)rel);
 
318
        if(index != -1)
 
319
                positionCombo->setCurrentIndex(index);
 
320
 
 
321
        /* Relative Output Name Configuration */
 
322
        foreach(OutputConfig *config, precedingOutputConfigs) {
 
323
                RandROutput* output = config->output();
 
324
                if( config->resolution().isEmpty())
 
325
                        continue; // ignore disabled outputs
 
326
                positionOutputCombo->addItem(QIcon(output->icon()), output->name(), (int)output->id());
 
327
                for( int rel = -1; rel < 5; ++rel ) {
 
328
                        if( isRelativeTo( rect, QRect( config->position(), config->resolution()), (Relation) rel )) {
 
329
                                positionCombo->setCurrentIndex( positionCombo->findData( rel ));
 
330
                        }
 
331
                }
 
332
        }
 
333
        if( positionOutputCombo->count() == 0 ) {
 
334
            positionOutputCombo->setEnabled( false );
 
335
            while( positionCombo->count() > 1 ) // keep only 'Absolute'
 
336
                positionCombo->removeItem( positionCombo->count() - 1 );
 
337
        }
 
338
 
 
339
        // FIXME: get this from Kconfig again
 
340
        /*if(m_output->relation(0) != m_output) {
 
341
                index = positionOutputCombo->findData((int)m_output->relation(0)->id());
 
342
                if(index != -1)
 
343
                        positionOutputCombo->setCurrentIndex(index);
 
344
        }*/
 
345
 
 
346
        connect(positionCombo,    SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
347
        connect(positionOutputCombo,    SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
 
348
}
 
349
 
 
350
void OutputConfig::updateRotationList(void)
 
351
{
 
352
        bool enable = !resolution().isEmpty();
 
353
        orientationCombo->setEnabled( enable );
 
354
        orientationLabel->setEnabled( enable );
 
355
        orientationCombo->clear();
 
356
        int rotations = m_output->rotations();
 
357
        for(int i =0; i < 6; ++i) {
 
358
                int rot = (1 << i);
 
359
                if (rot & rotations) {
 
360
                        orientationCombo->addItem(QIcon(RandR::rotationIcon(rot, RandR::Rotate0)), 
 
361
                                                  RandR::rotationName(rot), rot);
 
362
                }
 
363
        }
 
364
        
 
365
        int index = orientationCombo->findData(m_output->rotation());
 
366
        if (index != -1)
 
367
                orientationCombo->setCurrentIndex( index );
 
368
}
 
369
 
 
370
void OutputConfig::updateSizeList(void)
 
371
{
 
372
        SizeList sizes = m_output->sizes();
 
373
        RandRMode preferredMode = m_output->preferredMode();
 
374
        sizeCombo->clear();
 
375
        sizeCombo->addItem( i18nc("Screen size", "Disabled"), QSize(0, 0) );
 
376
        
 
377
        foreach (const QSize &s, sizes) {
 
378
                QString sizeDesc = QString("%1x%2").arg(s.width()).arg(s.height());
 
379
                if (preferredMode.isValid() && s == preferredMode.size()) {
 
380
                        sizeDesc = i18nc("Automatic screen size (native resolution)",
 
381
                                         "%1 (Auto)", sizeDesc);
 
382
                }
 
383
                sizeCombo->addItem( sizeDesc, s );
 
384
        }
 
385
        
 
386
        int index = -1;
 
387
 
 
388
    // if output is rotated 90 or 270 degrees, swap width and height before searching in combobox data
 
389
    // otherwise 90 or 270 degrees rotated outputs will be set as "Disabled" in GUI
 
390
        if (m_output->rotation() == RandR::Rotate90 || m_output->rotation() == RandR::Rotate270)
 
391
                index = sizeCombo->findData( QSize(m_output->rect().height(), m_output->rect().width()) );
 
392
        else
 
393
                index = sizeCombo->findData( m_output->rect().size() );
 
394
 
 
395
        if (index != -1)
 
396
                sizeCombo->setCurrentIndex( index );
 
397
    else
 
398
        kDebug() << "Output size cannot be matched!";
 
399
 
 
400
        index = refreshCombo->findData(m_output->refreshRate());
 
401
        if (index != -1)
 
402
                refreshCombo->setCurrentIndex(index);
 
403
}
 
404
 
 
405
void OutputConfig::updateRateList(int resolutionIndex)
 
406
{
 
407
        QSize resolution = sizeCombo->itemData(resolutionIndex).toSize();
 
408
        if((resolution == QSize(0, 0)) || !resolution.isValid()) {
 
409
                refreshCombo->setEnabled(false);
 
410
                rateLabel->setEnabled(false);
 
411
                return;
 
412
        }
 
413
        
 
414
        ModeList modeList = m_output->modes();
 
415
        
 
416
        refreshCombo->clear();
 
417
        refreshCombo->addItem(i18nc("Automatic refresh rate configuration", "Auto"), 0.0f);
 
418
        refreshCombo->setEnabled(true);
 
419
        rateLabel->setEnabled(true);
 
420
        foreach(RRMode m, modeList) {
 
421
                RandRMode outMode = m_output->screen()->mode(m);
 
422
                if(outMode.isValid() && outMode.size() == resolution) {
 
423
                        float rate = outMode.refreshRate();
 
424
                        refreshCombo->addItem(ki18n("%1 Hz").subs(rate, 0, 'f', 1).toString(), rate);
 
425
                }
 
426
        }
 
427
}
 
428
 
 
429
void OutputConfig::updateRateList()
 
430
{
 
431
        if (sizeCombo->currentIndex() == -1)
 
432
                return;
 
433
 
 
434
        // update the refresh rate list to reflect the currently selected
 
435
        // resolution
 
436
        updateRateList(sizeCombo->currentIndex());
 
437
}
 
438
 
 
439
#include "outputconfig.moc"