2
* Copyright (c) 2007 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
3
* Copyright (c) 2002,2003 Hamish Rodda <rodda@kde.org>
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 "krandrtray.h"
21
#include "krandrpassivepopup.h"
22
#include "krandrtray.moc"
23
#include "legacyrandrscreen.h"
25
#include "randrscreen.h"
26
#include "randroutput.h"
27
#include "randrmode.h"
30
#include <config-randr.h>
32
#include <QMouseEvent>
36
#include <KActionCollection>
37
#include <KApplication>
38
#include <KCMultiDialog>
39
#include <KComponentData>
42
#include <KIconLoader>
45
#include <KWindowSystem>
47
KRandRSystemTray::KRandRSystemTray(RandRDisplay *dpy, QWidget* parent)
48
: KStatusNotifierItem(parent),
49
m_help(new KHelpMenu(parent, KGlobal::mainComponent().aboutData(), false, actionCollection())),
53
setIconByName("preferences-desktop-display-randr");
54
setCategory(Hardware);
56
m_menu = new KMenu(associatedWidget());
57
setContextMenu(m_menu);
60
//TODO: probably we need an about to show signal
61
connect(m_menu, SIGNAL(aboutToShow()), this, SLOT(slotPrepareMenu()));
66
KRandRSystemTray::~KRandRSystemTray()
73
void KRandRSystemTray::activate(const QPoint &pos)
79
void KRandRSystemTray::slotPrepareMenu()
85
if (!m_display->isValid())
87
action = m_menu->addAction(i18n("Required X Extension Not Available"));
88
action->setEnabled(false);
93
m_screenPopups.clear();
94
for (int s = 0; s < m_display->numScreens(); s++)
96
m_display->setCurrentScreen(s);
97
if (s == m_display->screenIndexOfWidget(associatedWidget()))
99
/*lastIndex = menu->insertItem(i18n("Screen %1").arg(s+1));
100
menu->setItemEnabled(lastIndex, false);*/
104
KMenu* subMenu = new KMenu(i18n("Screen %1", s+1), m_menu );
105
subMenu->setObjectName( QString("screen%1").arg(s+1) );
106
m_screenPopups.append(subMenu);
107
populateMenu(subMenu);
108
action = m_menu->addMenu(subMenu);
109
connect(subMenu, SIGNAL(activated(int)), SLOT(slotScreenActivated()));
113
m_display->setCurrentScreen(m_display->screenIndexOfWidget(m_menu));
114
if (m_display->needsRefresh()) {
115
kDebug() << "Configuration dirty, reloading settings...";
116
m_display->refresh();
120
populateMenu(m_menu);
123
m_menu->addSeparator();
125
KAction *actPrefs = actionCollection()->addAction( QString() );
126
actPrefs->setIcon( KIcon( "configure" ) );
127
actPrefs->setText( i18n( "Configure Display..." ) );
129
connect( actPrefs, SIGNAL( triggered( bool ) ), SLOT( slotPrefs() ) );
130
m_menu->addAction( actPrefs );
132
m_menu->addMenu(/*SmallIcon("help-contents"),KStandardGuiItem::help().text(),*/ m_help->menu());
133
QAction *quitAction = actionCollection()->action(KStandardAction::name(KStandardAction::Quit));
134
m_menu->addAction( quitAction );
137
void KRandRSystemTray::slotScreenActivated()
139
m_display->setCurrentScreen(m_screenPopups.indexOf(static_cast<KMenu*>(sender())));
142
void KRandRSystemTray::updateToolTip()
144
const QString icon = "preferences-desktop-display-randr";
145
QString title = i18n("Display");
146
QString subTitle = i18n("Resize, rotate and configure screens.");
148
if (m_display->isValid())
150
OutputMap outputs = m_display->currentScreen()->outputs();
151
if (outputs.count() <= 0)
154
RandRScreen *screen = m_display->currentScreen();
157
if (screen->outputsUnified() && screen->connectedCount() > 1)
159
SizeList sizes = screen->unifiedSizes();
160
if (!sizes.isEmpty())
162
const QSize currentSize = screen->rect().size();
163
subTitle = i18n("Resolution: %1 x %2",
164
QString::number(currentSize.width()),
165
QString::number(currentSize.height()));
166
int rotations = screen->unifiedRotations();
167
if (rotations != RandR::Rotate0)
169
int rotation = RandR::Rotate0;
170
foreach (RandROutput *output, screen->outputs())
171
if (output->isActive())
173
rotation = output->rotation();
177
if (rotation != RandR::Rotate0)
178
subTitle += "<br>" + i18n("Rotation: %1", RandR::rotationName(1 << rotation));
184
QString details = "<table>";
185
foreach(RandROutput *output, outputs)
187
if (output->isConnected())
189
details += "<tr><td colspan=\"2\">" + output->name()
192
QSize currentSize = output->rect().size();
193
if (output->rotation() & (RandR::Rotate90 | RandR::Rotate270))
194
currentSize = QSize(currentSize.height(), currentSize.width());
196
details += "<tr>" + i18n("<td align=\"right\">Resolution: </td><td>%1 x %2</td></tr>",
197
QString::number(currentSize.width()),
198
QString::number(currentSize.height()));
199
RateList rates = output->refreshRates();
202
details += "<tr><td align=\"right\">" + i18n("Refresh: ") + "</td><td>"
203
+ ki18n("%1 Hz").subs(output->refreshRate(), 0, 'f', 1).toString()
207
int rotations = output->rotations();
208
if (rotations != RandR::Rotate0 &&
209
output->rotation() != RandR::Rotate0)
211
details += "<tr><td align=\"right\">" + i18n("Rotation: ") + "</td><td>"
212
+ RandR::rotationName(1 << output->rotation())
218
if (details != "<table>")
220
title = details + "</table>";
227
setToolTip(icon, title, subTitle);
230
void KRandRSystemTray::configChanged()
232
m_display->refresh();
234
static bool first = true;
241
// TODO: display config changed message
242
message = "Screen config changed";
245
message = m_display->currentLegacyScreen()->changedMessage();
247
KRandrPassivePopup::message(
248
i18n("Screen configuration has changed"),
249
message, SmallIcon("view-fullscreen"),
256
void KRandRSystemTray::populateMenu(KMenu* menu)
262
QActionGroup *actionGroup;
264
OutputMap outputs = m_display->currentScreen()->outputs();
265
if (outputs.count() <= 0)
268
RandRScreen *screen = m_display->currentScreen();
271
// if the outputs are unified, do not show output-specific size
272
// changing options in the tray.
273
if (screen->outputsUnified() && screen->connectedCount() > 1)
275
SizeList sizes = screen->unifiedSizes();
279
// populate unified sizes
281
currentSize = screen->rect().size();
283
menu->addTitle(SmallIcon("view-fullscreen"), i18n("Screen Size"));
284
actionGroup = populateSizes(menu, sizes, currentSize);
285
connect(actionGroup, SIGNAL(triggered(QAction*)), screen, SLOT(slotResizeUnified(QAction*)));
287
// if the outputs are unified, we can rotate the screen on all outputs
288
int rotations = screen->unifiedRotations();
289
if (rotations != RandR::Rotate0)
291
menu->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
292
int rotation = RandR::Rotate0;
293
foreach(RandROutput *output, screen->outputs())
294
if (output->isActive())
296
rotation = output->rotation();
300
actionGroup = populateRotations(menu, rotations, rotation);
301
connect(actionGroup, SIGNAL(triggered(QAction*)), screen, SLOT(slotRotateUnified(QAction*)));
307
if (screen->connectedCount() != 1)
308
menu->addTitle(SmallIcon("view-fullscreen"), i18n("Outputs"));
311
RandROutput *primary = screen->primaryOutput();
312
#endif //HAS_RANDR_1_3
314
foreach(RandROutput *output, outputs)
316
if (output->isConnected())
319
if (screen->connectedCount() == 1)
322
outputMenu = new KMenu(output->name());
323
outputMenu->setIcon(SmallIcon(output->icon()));
324
outputMenu->addTitle(SmallIcon("view-fullscreen"), i18n("%1 - Screen Size", output->name()));
326
QSize currentSize = output->rect().size();
328
// if the output is rotated 90 or 270, the returned rect is inverted
329
// so we need to invert the size before comparing
330
if (output->rotation() & (RandR::Rotate90 | RandR::Rotate270))
331
currentSize = QSize(currentSize.height(), currentSize.width());
333
actionGroup = populateSizes(outputMenu, output->sizes(), currentSize);
334
connect(actionGroup, SIGNAL(triggered(QAction*)), output, SLOT(slotChangeSize(QAction*)));
336
// if there is only one output active, do not show the disable option
337
// this prevents the user from doing wrong things ;)
338
kDebug() << "Active outputs: " << screen->activeCount();
339
if (screen->activeCount() != 1)
341
action = outputMenu->addAction(i18n("Disable"));
342
if (output->crtc() == None)
344
QFont font = action->font();
346
action->setFont(font);
348
connect(action, SIGNAL(triggered(bool)), output, SLOT(slotDisable()));
351
// Display the rotations
352
int rotations = output->rotations();
353
// Don't display the rotation options if there is no point (ie. none are supported)
354
// XFree86 4.3 does not include rotation support.
355
if (rotations != RandR::Rotate0)
357
outputMenu->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
358
actionGroup = populateRotations(outputMenu, rotations, output->rotation());
359
connect(actionGroup, SIGNAL(triggered(QAction*)),
360
output, SLOT(slotChangeRotation(QAction*)));
364
RateList rates = output->refreshRates();
367
outputMenu->addTitle(SmallIcon("chronometer"), i18n("Refresh Rate"));
368
actionGroup = populateRates(outputMenu, rates, output->refreshRate());
369
connect(actionGroup, SIGNAL(triggered(QAction*)),
370
output, SLOT(slotChangeRefreshRate(QAction*)));
374
if (RandR::has_1_3 && screen->connectedCount() != 1)
376
outputMenu->addSeparator();
377
action = outputMenu->addAction(
378
i18nc("(checkbox) designate this output as the primary output", "Primary output"),
380
SLOT(slotSetAsPrimary(bool)) );
381
action->setCheckable(true);
382
action->setChecked(primary == output);
384
#endif //HAS_RANDR_1_3
387
if (screen->connectedCount() != 1)
388
menu->addMenu(outputMenu);
392
// if there is more than one output connected, give the option to unify the outputs
393
if (screen->connectedCount() != 1)
395
menu->addSeparator();
396
action = menu->addAction( i18n("Unify Outputs"), screen, SLOT(slotUnifyOutputs(bool)) );
397
action->setCheckable(true);
398
action->setChecked(screen->outputsUnified());
403
populateLegacyMenu(menu);
406
void KRandRSystemTray::populateLegacyMenu(KMenu* menu)
408
menu->addTitle(SmallIcon("view-fullscreen"), i18n("Screen Size"));
410
LegacyRandRScreen *screen = m_display->currentLegacyScreen();
414
QActionGroup *screenSizeGroup = populateSizes(menu, RandR::sortSizes(screen->pixelSizes()), screen->currentPixelSize());
415
connect(screenSizeGroup, SIGNAL(triggered(QAction*)), SLOT(slotResolutionChanged(QAction*)));
417
// Don't display the rotation options if there is no point (ie. none are supported)
418
// XFree86 4.3 does not include rotation support.
419
if (screen->rotations() != RandR::Rotate0)
421
menu->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
423
QActionGroup *rotationGroup = populateRotations(menu, screen->rotations(), screen->rotation());
424
connect(rotationGroup, SIGNAL(triggered(QAction*)), SLOT(slotOrientationChanged(QAction*)));
427
RateList rr = screen->refreshRates(screen->proposedSize());
430
menu->addTitle(SmallIcon("clock"), i18n("Refresh Rate"));
432
QActionGroup *rateGroup = populateRates(menu, rr, screen->refreshRate());
433
connect(rateGroup, SIGNAL(triggered(QAction*)), SLOT(slotRefreshRateChanged(QAction*)));
437
QActionGroup *KRandRSystemTray::populateRotations(KMenu *menu, int rotations, int rotation)
440
QActionGroup *rotateGroup = new QActionGroup(menu);
441
rotateGroup->setExclusive(true);
443
for (int i = 0; i < 6; i++)
445
if ((1 << i) & rotations)
447
action = menu->addAction(QIcon(RandR::rotationIcon(1 << i, rotation)),
448
RandR::rotationName(1 << i));
449
action->setCheckable(true);
451
action->setData(1 << i);
452
if (rotation & (1 << i))
454
action->setChecked(true);
456
rotateGroup->addAction(action);
462
QActionGroup *KRandRSystemTray::populateSizes(KMenu *menu, const SizeList &sizes, const QSize &size)
465
QActionGroup *sizeGroup = new QActionGroup(menu);
466
sizeGroup->setExclusive(true);
467
for (int i = 0; i < sizes.count(); ++i)
470
action = menu->addAction(QString("%1 x %2").arg(s.width()).arg(s.height()));
471
action->setCheckable(true);
475
action->setChecked(true);
477
sizeGroup->addAction(action);
482
QActionGroup *KRandRSystemTray::populateRates(KMenu *menu, const RateList &rates, float rate)
485
QActionGroup *rateGroup = new QActionGroup(menu);
486
rateGroup->setExclusive(true);
488
foreach(float r, rates)
490
action = menu->addAction(ki18n("%1 Hz").subs(r, 0, 'f', 1).toString());
491
action->setCheckable(true);
495
action->setChecked(true);
497
rateGroup->addAction(action);
502
void KRandRSystemTray::slotResolutionChanged(QAction *action)
504
LegacyRandRScreen *screen = m_display->currentLegacyScreen();
507
QSize s = action->data().toSize();
509
const SizeList pixelSizes = screen->pixelSizes();
510
for (int i = 0; i < pixelSizes.count(); ++i)
511
if (pixelSizes[i] == s)
517
if (screen->size() == index)
520
screen->proposeSize(index);
522
screen->proposeRefreshRate(-1);
524
if (screen->applyProposedAndConfirm())
526
KConfig config("krandrrc");
527
if (m_display->syncTrayApp(config))
528
screen->save(config);
532
void KRandRSystemTray::slotOrientationChanged(QAction *action)
534
LegacyRandRScreen *screen = m_display->currentLegacyScreen();
537
int propose = screen->rotation();
538
int rotate = action->data().toInt();
540
if (rotate & RandR::RotateMask)
541
propose &= RandR::ReflectMask;
545
if (screen->rotation() == propose)
548
screen->proposeRotation(propose);
550
if (screen->applyProposedAndConfirm())
552
KConfig config("krandrrc");
553
if (m_display->syncTrayApp(config))
554
screen->save(config);
558
void KRandRSystemTray::slotRefreshRateChanged(QAction *action)
560
LegacyRandRScreen *screen = m_display->currentLegacyScreen();
563
int index = action->data().toInt();
565
if (screen->refreshRate() == index)
568
screen->proposeRefreshRate(index);
570
if (screen->applyProposedAndConfirm())
572
KConfig config("krandrrc");
573
if (m_display->syncTrayApp(config))
574
screen->save(config);
578
void KRandRSystemTray::slotPrefs()
582
KCMultiDialog *kcm = new KCMultiDialog( associatedWidget() );
583
kcm->setFaceType( KCMultiDialog::Plain );
584
kcm->setPlainCaption( i18n( "Configure Display" ) );
585
kcm->addModule( "display" );
586
kcm->setAttribute(Qt::WA_DeleteOnClose);
590
KWindowSystem::setOnDesktop(m_kcm.data()->winId(), KWindowSystem::currentDesktop());
591
m_kcm.data()->show();
592
m_kcm.data()->raise();
594
// vim:noet:sts=8:sw=8: