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 <KActionCollection>
33 #include <KApplication>
34 #include <KCMultiDialog>
35 #include <KComponentData>
38 #include <KIconLoader>
42 #include <QMouseEvent>
45 KRandRSystemTray::KRandRSystemTray(RandRDisplay
*dpy
, QWidget
* parent
)
46 : KSystemTrayIcon("preferences-desktop-display-randr", parent
),
47 m_help(new KHelpMenu(parent
, KGlobal::mainComponent().aboutData(), false, actionCollection())),
51 setIcon(KSystemTrayIcon::loadIcon("preferences-desktop-display-randr"));
52 connect(this, SIGNAL(quitSelected()), kapp
, SLOT(quit()));
53 this->setToolTip( i18n("Screen resize & rotate"));
55 m_menu
= new KMenu(parentWidget());
56 setContextMenu(m_menu
);
58 connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason
)), SLOT(slotActivated(QSystemTrayIcon::ActivationReason
)));
60 connect(m_menu
, SIGNAL(aboutToShow()), this, SLOT(slotPrepareMenu()));
64 void KRandRSystemTray::slotActivated(QSystemTrayIcon::ActivationReason reason
)
66 if(reason
== QSystemTrayIcon::DoubleClick
) {
71 void KRandRSystemTray::slotPrepareMenu()
77 if (!m_display
->isValid())
79 action
= m_menu
->addAction(i18n("Required X Extension Not Available"));
80 action
->setEnabled(false);
85 m_screenPopups
.clear();
86 for (int s
= 0; s
< m_display
->numScreens(); s
++)
88 m_display
->setCurrentScreen(s
);
89 if (s
== m_display
->screenIndexOfWidget(parentWidget()))
91 /*lastIndex = menu->insertItem(i18n("Screen %1").arg(s+1));
92 menu->setItemEnabled(lastIndex, false);*/
96 KMenu
* subMenu
= new KMenu(i18n("Screen %1", s
+1), m_menu
);
97 subMenu
->setObjectName( QString("screen%1").arg(s
+1) );
98 m_screenPopups
.append(subMenu
);
99 populateMenu(subMenu
);
100 action
= m_menu
->addMenu(subMenu
);
101 connect(subMenu
, SIGNAL(activated(int)), SLOT(slotScreenActivated()));
105 m_display
->setCurrentScreen(m_display
->screenIndexOfWidget(m_menu
));
106 if (m_display
->needsRefresh()) {
107 kDebug() << "Configuration dirty, reloading settings...";
108 m_display
->refresh();
111 populateMenu(m_menu
);
114 m_menu
->addSeparator();
116 KAction
*actPrefs
= actionCollection()->addAction( QString() );
117 actPrefs
->setIcon( KIcon( "configure" ) );
118 actPrefs
->setText( i18n( "Configure Display..." ) );
120 connect( actPrefs
, SIGNAL( triggered( bool ) ), SLOT( slotPrefs() ) );
121 m_menu
->addAction( actPrefs
);
123 m_menu
->addMenu(/*SmallIcon("help-contents"),KStandardGuiItem::help().text(),*/ m_help
->menu());
124 QAction
*quitAction
= actionCollection()->action(KStandardAction::name(KStandardAction::Quit
));
125 m_menu
->addAction( quitAction
);
128 void KRandRSystemTray::slotScreenActivated()
130 m_display
->setCurrentScreen(m_screenPopups
.indexOf(static_cast<KMenu
*>(sender())));
133 void KRandRSystemTray::configChanged()
135 m_display
->refresh();
137 static bool first
= true;
144 // TODO: display config changed message
145 message
= "Screen config changed";
148 message
= m_display
->currentLegacyScreen()->changedMessage();
150 KRandrPassivePopup::message(
151 i18n("Screen configuration has changed"),
152 message
, SmallIcon("view-fullscreen"),
159 void KRandRSystemTray::populateMenu(KMenu
* menu
)
165 QActionGroup
*actionGroup
;
167 OutputMap outputs
= m_display
->currentScreen()->outputs();
168 if (outputs
.count() <= 0)
171 RandRScreen
*screen
= m_display
->currentScreen();
174 // if the outputs are unified, do not show output-specific size
175 // changing options in the tray.
176 if (screen
->outputsUnified() && screen
->connectedCount() > 1)
178 SizeList sizes
= screen
->unifiedSizes();
182 // populate unified sizes
184 currentSize
= screen
->rect().size();
186 menu
->addTitle(SmallIcon("view-fullscreen"), i18n("Screen Size"));
187 actionGroup
= populateSizes(menu
, sizes
, currentSize
);
188 connect(actionGroup
, SIGNAL(triggered(QAction
*)), screen
, SLOT(slotResizeUnified(QAction
*)));
190 // if the outputs are unified, we can rotate the screen on all outputs
191 int rotations
= screen
->unifiedRotations();
192 if (rotations
!= RandR::Rotate0
)
194 menu
->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
195 int rotation
= RandR::Rotate0
;
196 foreach(RandROutput
*output
, screen
->outputs())
197 if (output
->isActive())
199 rotation
= output
->rotation();
203 actionGroup
= populateRotations(menu
, rotations
, rotation
);
204 connect(actionGroup
, SIGNAL(triggered(QAction
*)), screen
, SLOT(slotRotateUnified(QAction
*)));
210 if (screen
->connectedCount() != 1)
211 menu
->addTitle(SmallIcon("view-fullscreen"), i18n("Outputs"));
213 foreach(RandROutput
*output
, outputs
)
215 if (output
->isConnected())
218 if (screen
->connectedCount() == 1)
221 outputMenu
= new KMenu(output
->name());
222 outputMenu
->setIcon(SmallIcon(output
->icon()));
223 outputMenu
->addTitle(SmallIcon("view-fullscreen"), i18n("%1 - Screen Size", output
->name()));
225 QSize currentSize
= output
->rect().size();
227 // if the output is rotated 90 or 270, the returned rect is inverted
228 // so we need to invert the size before comparing
229 if (output
->rotation() & (RandR::Rotate90
| RandR::Rotate270
))
230 currentSize
= QSize(currentSize
.height(), currentSize
.width());
232 actionGroup
= populateSizes(outputMenu
, output
->sizes(), currentSize
);
233 connect(actionGroup
, SIGNAL(triggered(QAction
*)), output
, SLOT(slotChangeSize(QAction
*)));
235 // if there is only one output active, do not show the disable option
236 // this prevents the user from doing wrong things ;)
237 kDebug() << "Active outputs: " << screen
->activeCount();
238 if (screen
->activeCount() != 1)
240 action
= outputMenu
->addAction(i18n("Disable"));
241 if (output
->crtc() == None
)
243 QFont font
= action
->font();
245 action
->setFont(font
);
247 connect(action
, SIGNAL(triggered(bool)), output
, SLOT(slotDisable()));
250 // Display the rotations
251 int rotations
= output
->rotations();
252 // Don't display the rotation options if there is no point (ie. none are supported)
253 // XFree86 4.3 does not include rotation support.
254 if (rotations
!= RandR::Rotate0
)
256 outputMenu
->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
257 actionGroup
= populateRotations(outputMenu
, rotations
, output
->rotation());
258 connect(actionGroup
, SIGNAL(triggered(QAction
*)),
259 output
, SLOT(slotChangeRotation(QAction
*)));
263 RateList rates
= output
->refreshRates();
266 outputMenu
->addTitle(SmallIcon("chronometer"), i18n("Refresh Rate"));
267 actionGroup
= populateRates(outputMenu
, rates
, output
->refreshRate());
268 connect(actionGroup
, SIGNAL(triggered(QAction
*)),
269 output
, SLOT(slotChangeRefreshRate(QAction
*)));
272 if (screen
->connectedCount() != 1)
273 menu
->addMenu(outputMenu
);
277 // if there is more than one output connected, give the option to unify the outputs
278 if (screen
->connectedCount() != 1)
280 menu
->addSeparator();
281 action
= menu
->addAction( i18n("Unify Outputs"), screen
, SLOT(slotUnifyOutputs(bool)) );
282 action
->setCheckable(true);
283 action
->setChecked(screen
->outputsUnified());
288 populateLegacyMenu(menu
);
291 void KRandRSystemTray::populateLegacyMenu(KMenu
* menu
)
293 menu
->addTitle(SmallIcon("view-fullscreen"), i18n("Screen Size"));
295 LegacyRandRScreen
*screen
= m_display
->currentLegacyScreen();
299 QActionGroup
*screenSizeGroup
= populateSizes(menu
, RandR::sortSizes(screen
->pixelSizes()), screen
->currentPixelSize());
300 connect(screenSizeGroup
, SIGNAL(triggered(QAction
*)), SLOT(slotResolutionChanged(QAction
*)));
302 // Don't display the rotation options if there is no point (ie. none are supported)
303 // XFree86 4.3 does not include rotation support.
304 if (screen
->rotations() != RandR::Rotate0
)
306 menu
->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
308 QActionGroup
*rotationGroup
= populateRotations(menu
, screen
->rotations(), screen
->rotation());
309 connect(rotationGroup
, SIGNAL(triggered(QAction
*)), SLOT(slotOrientationChanged(QAction
*)));
312 RateList rr
= screen
->refreshRates(screen
->proposedSize());
315 menu
->addTitle(SmallIcon("clock"), i18n("Refresh Rate"));
317 QActionGroup
*rateGroup
= populateRates(menu
, rr
, screen
->refreshRate());
318 connect(rateGroup
, SIGNAL(triggered(QAction
*)), SLOT(slotRefreshRateChanged(QAction
*)));
322 QActionGroup
*KRandRSystemTray::populateRotations(KMenu
*menu
, int rotations
, int rotation
)
325 QActionGroup
*rotateGroup
= new QActionGroup(menu
);
328 for (int i
= 0; i
< 6; i
++)
330 if ((1 << i
) & rotations
)
332 action
= menu
->addAction(QIcon(RandR::rotationIcon(1 << i
, rotation
)),
333 RandR::rotationName(1 << i
));
335 action
->setData(1 << i
);
336 if (rotation
& (1 << i
))
338 QFont font
= action
->font();
340 action
->setFont(font
);
342 rotateGroup
->addAction(action
);
348 QActionGroup
*KRandRSystemTray::populateSizes(KMenu
*menu
, const SizeList
&sizes
, const QSize
&size
)
351 QActionGroup
*sizeGroup
= new QActionGroup(menu
);
352 for (int i
= 0; i
< sizes
.count(); ++i
)
355 action
= menu
->addAction(QString("%1 x %2").arg(s
.width()).arg(s
.height()));
359 QFont font
= action
->font();
361 action
->setFont(font
);
363 sizeGroup
->addAction(action
);
368 QActionGroup
*KRandRSystemTray::populateRates(KMenu
*menu
, const RateList
&rates
, float rate
)
371 QActionGroup
*rateGroup
= new QActionGroup(menu
);
373 foreach(float r
, rates
)
375 action
= menu
->addAction(ki18n("%1 Hz").subs(r
, 0, 'f', 1).toString());
379 QFont f
= action
->font();
383 rateGroup
->addAction(action
);
388 void KRandRSystemTray::slotResolutionChanged(QAction
*action
)
390 LegacyRandRScreen
*screen
= m_display
->currentLegacyScreen();
393 QSize s
= action
->data().toSize();
395 const SizeList pixelSizes
= screen
->pixelSizes();
396 for (int i
= 0; i
< pixelSizes
.count(); ++i
)
397 if (pixelSizes
[i
] == s
)
403 if (screen
->size() == index
)
406 screen
->proposeSize(index
);
408 screen
->proposeRefreshRate(-1);
410 if (screen
->applyProposedAndConfirm())
412 KConfig
config("krandrrc");
413 if (m_display
->syncTrayApp(config
))
414 screen
->save(config
);
418 void KRandRSystemTray::slotOrientationChanged(QAction
*action
)
420 LegacyRandRScreen
*screen
= m_display
->currentLegacyScreen();
423 int propose
= screen
->rotation();
424 int rotate
= action
->data().toInt();
426 if (rotate
& RandR::RotateMask
)
427 propose
&= RandR::ReflectMask
;
431 if (screen
->rotation() == propose
)
434 screen
->proposeRotation(propose
);
436 if (screen
->applyProposedAndConfirm())
438 KConfig
config("krandrrc");
439 if (m_display
->syncTrayApp(config
))
440 screen
->save(config
);
444 void KRandRSystemTray::slotRefreshRateChanged(QAction
*action
)
446 LegacyRandRScreen
*screen
= m_display
->currentLegacyScreen();
449 int index
= action
->data().toInt();
451 if (screen
->refreshRate() == index
)
454 screen
->proposeRefreshRate(index
);
456 if (screen
->applyProposedAndConfirm())
458 KConfig
config("krandrrc");
459 if (m_display
->syncTrayApp(config
))
460 screen
->save(config
);
464 void KRandRSystemTray::slotPrefs()
466 KCMultiDialog
*kcm
= new KCMultiDialog( parentWidget() );
467 kcm
->setFaceType( KCMultiDialog::Plain
);
468 kcm
->setPlainCaption( i18n( "Configure Display" ) );
469 kcm
->addModule( "display" );