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 "outputconfig.h"
21
#include "outputgraphicsitem.h"
22
#include "randroutput.h"
23
#include "randrscreen.h"
24
#include "randrmode.h"
27
OutputConfig::OutputConfig(QWidget *parent, RandROutput *output, OutputConfigList preceding)
29
, precedingOutputConfigs( preceding )
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)));
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()));
65
updatePositionListTimer.setSingleShot( true );
66
connect( &updatePositionListTimer, SIGNAL( timeout()), SLOT( updatePositionListDelayed()));
70
OutputConfig::~OutputConfig()
74
RandROutput *OutputConfig::output(void) const
79
QPoint OutputConfig::position(void) const
83
int index = positionCombo->currentIndex();
84
if((Relation)positionCombo->itemData(index).toInt() == Absolute)
85
return QPoint(absolutePosX->text().toInt(), absolutePosY->text().toInt());
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()) {
93
return QPoint( pos.x() - resolution().width(), pos.y());
95
return QPoint( pos.x() + config->resolution().width(), pos.y());
97
return QPoint( pos.x(), pos.y() - resolution().height());
99
return QPoint( pos.x(), pos.y() + config->resolution().height());
110
QSize OutputConfig::resolution(void) const
112
if( sizeCombo->count() == 0 )
114
return sizeCombo->itemData(sizeCombo->currentIndex()).toSize();
117
QRect OutputConfig::rect() const
119
return QRect( position(), resolution());
122
bool OutputConfig::isActive() const
124
return sizeCombo->count() != 0 && !resolution().isEmpty();
127
float OutputConfig::refreshRate(void) const
131
float rate = float(refreshCombo->itemData(refreshCombo->currentIndex()).toDouble());
133
RateList rates = m_output->refreshRates(resolution());
134
return rates.first();
139
int OutputConfig::rotation(void) const
143
return orientationCombo->itemData(orientationCombo->currentIndex()).toInt();
146
bool OutputConfig::hasPendingChanges( const QPoint& normalizePos ) const
148
if (m_output->rect().translated( -normalizePos ) != QRect(position(), resolution())) {
151
else if (m_output->rotation() != rotation()) {
154
else if (m_output->refreshRate() != refreshRate()) {
160
void OutputConfig::outputChanged(RROutput output, int changes)
162
Q_ASSERT(m_output->id() == output); Q_UNUSED(output);
163
kDebug() << "Output" << m_output->name() << "changed. ( mask =" << QString::number(changes) << ")";
165
if(changes & RandR::ChangeOutputs) {
166
kDebug() << "Outputs changed.";
169
if(changes & RandR::ChangeCrtc) {
170
kDebug() << "Output CRTC changed.";
174
updateRotationList();
177
if(changes & RandR::ChangeRect) {
178
QRect r = m_output->rect();
179
kDebug() << "Output rect changed:" << r;
182
if(changes & RandR::ChangeRotation) {
183
kDebug() << "Output rotation changed.";
184
updateRotationList();
187
if(changes & RandR::ChangeConnection) {
188
kDebug() << "Output connection status changed.";
189
setEnabled(m_output->isConnected());
192
if(changes & RandR::ChangeRate) {
193
kDebug() << "Output rate changed.";
197
if(changes & RandR::ChangeMode) {
198
kDebug() << "Output mode changed.";
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));
208
QString OutputConfig::positionName(Relation 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");
219
return i18n("No relative position");
222
void OutputConfig::load()
224
kDebug() << "Loading output configuration for" << m_output->name();
225
setEnabled( m_output->isConnected() );
227
orientationCombo->clear();
229
if (!m_output->isConnected())
232
/* Mode size configuration */
235
/* Output rotation and relative position */
236
updateRotationList();
237
updatePositionList();
242
void OutputConfig::setConfigDirty(void)
245
emit optionChanged();
248
bool OutputConfig::isRelativeTo( QRect rect, QRect to, Relation rel )
252
return rect.x() + rect.width() == to.x() && rect.y() == to.y();
254
return rect.x() == to.x() + to.width() && rect.y() == to.y();
256
return rect.x() == to.x() && rect.y() + rect.height() == to.y();
258
return rect.x() == to.x() && rect.y() == to.y() + to.height();
260
return rect.topLeft() == to.topLeft();
267
void OutputConfig::positionComboChanged(int item)
270
rel = (Relation)positionCombo->itemData(item).toInt();
272
bool isAbsolute = (rel == Absolute);
274
positionOutputCombo->setVisible(!isAbsolute);
275
absolutePosX->setVisible(isAbsolute);
276
absolutePosY->setVisible(isAbsolute);
279
int posX = m_output->rect().topLeft().x();
280
int posY = m_output->rect().topLeft().y();
282
absolutePosX->setText(QString::number(posX));
283
absolutePosY->setText(QString::number(posY));
287
void OutputConfig::updatePositionList(void)
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 );
296
void OutputConfig::updatePositionListDelayed()
298
disconnect(positionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
299
disconnect(positionOutputCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
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();
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);
317
int index = positionCombo->findData((int)rel);
319
positionCombo->setCurrentIndex(index);
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 ));
333
if( positionOutputCombo->count() == 0 ) {
334
positionOutputCombo->setEnabled( false );
335
while( positionCombo->count() > 1 ) // keep only 'Absolute'
336
positionCombo->removeItem( positionCombo->count() - 1 );
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());
343
positionOutputCombo->setCurrentIndex(index);
346
connect(positionCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
347
connect(positionOutputCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setConfigDirty()));
350
void OutputConfig::updateRotationList(void)
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) {
359
if (rot & rotations) {
360
orientationCombo->addItem(QIcon(RandR::rotationIcon(rot, RandR::Rotate0)),
361
RandR::rotationName(rot), rot);
365
int index = orientationCombo->findData(m_output->rotation());
367
orientationCombo->setCurrentIndex( index );
370
void OutputConfig::updateSizeList(void)
372
SizeList sizes = m_output->sizes();
373
RandRMode preferredMode = m_output->preferredMode();
375
sizeCombo->addItem( i18nc("Screen size", "Disabled"), QSize(0, 0) );
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);
383
sizeCombo->addItem( sizeDesc, s );
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()) );
393
index = sizeCombo->findData( m_output->rect().size() );
396
sizeCombo->setCurrentIndex( index );
398
kDebug() << "Output size cannot be matched!";
400
index = refreshCombo->findData(m_output->refreshRate());
402
refreshCombo->setCurrentIndex(index);
405
void OutputConfig::updateRateList(int resolutionIndex)
407
QSize resolution = sizeCombo->itemData(resolutionIndex).toSize();
408
if((resolution == QSize(0, 0)) || !resolution.isValid()) {
409
refreshCombo->setEnabled(false);
410
rateLabel->setEnabled(false);
414
ModeList modeList = m_output->modes();
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);
429
void OutputConfig::updateRateList()
431
if (sizeCombo->currentIndex() == -1)
434
// update the refresh rate list to reflect the currently selected
436
updateRateList(sizeCombo->currentIndex());
439
#include "outputconfig.moc"