Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / kcontrol / randr / krandrtray.cpp
blob54271b7b26fc2bcbbb84301fd5198e92cdbdf5af
1 /*
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"
24 #ifdef HAS_RANDR_1_2
25 #include "randrscreen.h"
26 #include "randroutput.h"
27 #include "randrmode.h"
28 #endif
30 #include <config-randr.h>
32 #include <KActionCollection>
33 #include <KApplication>
34 #include <KCMultiDialog>
35 #include <KComponentData>
36 #include <KHelpMenu>
37 #include <KIcon>
38 #include <KIconLoader>
39 #include <KLocale>
40 #include <KMenu>
41 #include <KAction>
42 #include <QMouseEvent>
43 #include <QVariant>
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())),
48 m_popupUp(false),
49 m_display(dpy)
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(m_menu, SIGNAL(aboutToShow()), this, SLOT(slotPrepareMenu()));
61 void KRandRSystemTray::slotPrepareMenu()
63 QAction *action;
65 m_menu->clear();
67 if (!m_display->isValid())
69 action = m_menu->addAction(i18n("Required X Extension Not Available"));
70 action->setEnabled(false);
73 else
75 m_screenPopups.clear();
76 for (int s = 0; s < m_display->numScreens(); s++)
78 m_display->setCurrentScreen(s);
79 if (s == m_display->screenIndexOfWidget(parentWidget()))
81 /*lastIndex = menu->insertItem(i18n("Screen %1").arg(s+1));
82 menu->setItemEnabled(lastIndex, false);*/
84 else
86 KMenu* subMenu = new KMenu(i18n("Screen %1", s+1), m_menu );
87 subMenu->setObjectName( QString("screen%1").arg(s+1) );
88 m_screenPopups.append(subMenu);
89 populateMenu(subMenu);
90 action = m_menu->addMenu(subMenu);
91 connect(subMenu, SIGNAL(activated(int)), SLOT(slotScreenActivated()));
95 m_display->setCurrentScreen(m_display->screenIndexOfWidget(parentWidget()));
96 #ifdef HAS_RANDR_1_2
97 if (RandR::has_1_2)
98 m_display->currentScreen()->loadSettings(true);
99 #endif
100 populateMenu(m_menu);
103 m_menu->addSeparator();
105 KAction *actPrefs = actionCollection()->addAction( QString() );
106 actPrefs->setIcon( KIcon( "configure" ) );
107 actPrefs->setText( i18n( "Configure Display..." ) );
109 connect( actPrefs, SIGNAL( triggered( bool ) ), SLOT( slotPrefs() ) );
110 m_menu->addAction( actPrefs );
112 m_menu->addMenu(/*SmallIcon("help-contents"),KStandardGuiItem::help().text(),*/ m_help->menu());
113 QAction *quitAction = actionCollection()->action(KStandardAction::name(KStandardAction::Quit));
114 m_menu->addAction( quitAction );
117 void KRandRSystemTray::slotScreenActivated()
119 m_display->setCurrentScreen(m_screenPopups.indexOf(static_cast<KMenu*>(sender())));
122 void KRandRSystemTray::configChanged()
124 m_display->refresh();
126 static bool first = true;
128 if (!first)
130 QString message;
131 #ifdef HAS_RANDR_1_2
132 if (RandR::has_1_2)
133 // TODO: display config changed message
134 message = "Screen config changed";
135 else
136 #endif
137 message = m_display->currentLegacyScreen()->changedMessage();
139 KRandrPassivePopup::message(
140 i18n("Screen configuration has changed"),
141 message, SmallIcon("view-fullscreen"),
142 parentWidget());
145 first = false;
148 void KRandRSystemTray::populateMenu(KMenu* menu)
150 #ifdef HAS_RANDR_1_2
151 if (RandR::has_1_2)
153 QAction *action;
154 QActionGroup *actionGroup;
156 OutputMap outputs = m_display->currentScreen()->outputs();
157 if (outputs.count() <= 0)
158 return;
160 RandRScreen *screen = m_display->currentScreen();
161 Q_ASSERT(screen);
163 // if the outputs are unified, do not show output-specific size
164 // changing options in the tray.
165 if (screen->outputsUnified() && screen->connectedCount() > 1)
167 SizeList sizes = screen->unifiedSizes();
169 if (sizes.count())
171 // populate unified sizes
172 QSize currentSize;
173 currentSize = screen->rect().size();
175 menu->addTitle(SmallIcon("view-fullscreen"), i18n("Screen Size"));
176 actionGroup = populateSizes(menu, sizes, currentSize);
177 connect(actionGroup, SIGNAL(triggered(QAction*)), screen, SLOT(slotResizeUnified(QAction*)));
179 // if the outputs are unified, we can rotate the screen on all outputs
180 int rotations = screen->unifiedRotations();
181 if (rotations != RandR::Rotate0)
183 menu->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
184 int rotation = RandR::Rotate0;
185 foreach(RandROutput *output, screen->outputs())
186 if (output->isActive())
188 rotation = output->rotation();
189 break;
192 actionGroup = populateRotations(menu, rotations, rotation);
193 connect(actionGroup, SIGNAL(triggered(QAction*)), screen, SLOT(slotRotateUnified(QAction*)));
197 else
199 if (screen->connectedCount() != 1)
200 menu->addTitle(SmallIcon("view-fullscreen"), i18n("Outputs"));
202 foreach(RandROutput *output, outputs)
204 if (output->isConnected())
206 KMenu *outputMenu;
207 if (screen->connectedCount() == 1)
208 outputMenu = menu;
209 else
210 outputMenu = new KMenu(output->name());
211 outputMenu->setIcon(SmallIcon(output->icon()));
212 outputMenu->addTitle(SmallIcon("view-fullscreen"), i18n("%1 - Screen Size", output->name()));
214 QSize currentSize = output->rect().size();
216 // if the output is rotated 90 or 270, the returned rect is inverted
217 // so we need to invert the size before comparing
218 if (output->rotation() & (RandR::Rotate90 | RandR::Rotate270))
219 currentSize = QSize(currentSize.height(), currentSize.width());
221 actionGroup = populateSizes(outputMenu, output->sizes(), currentSize);
222 connect(actionGroup, SIGNAL(triggered(QAction*)), output, SLOT(slotChangeSize(QAction*)));
224 // if there is only one output active, do not show the disable option
225 // this prevents the user from doing wrong things ;)
226 kDebug() << "Active outputs: " << screen->activeCount();
227 if (screen->activeCount() != 1)
229 action = outputMenu->addAction(i18n("Disable"));
230 if (output->crtc() == None)
232 QFont font = action->font();
233 font.setBold(true);
234 action->setFont(font);
236 connect(action, SIGNAL(triggered(bool)), output, SLOT(slotDisable()));
239 // Display the rotations
240 int rotations = output->rotations();
241 // Don't display the rotation options if there is no point (ie. none are supported)
242 // XFree86 4.3 does not include rotation support.
243 if (rotations != RandR::Rotate0)
245 outputMenu->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
246 actionGroup = populateRotations(outputMenu, rotations, output->rotation());
247 connect(actionGroup, SIGNAL(triggered(QAction*)),
248 output, SLOT(slotChangeRotation(QAction*)));
251 // refresh rate
252 RateList rates = output->refreshRates();
253 if (rates.count())
255 outputMenu->addTitle(SmallIcon("chronometer"), i18n("Refresh Rate"));
256 actionGroup = populateRates(outputMenu, rates, output->refreshRate());
257 connect(actionGroup, SIGNAL(triggered(QAction*)),
258 output, SLOT(slotChangeRefreshRate(QAction*)));
261 if (screen->connectedCount() != 1)
262 menu->addMenu(outputMenu);
266 // if there is more than one output connected, give the option to unify the outputs
267 if (screen->connectedCount() != 1)
269 menu->addSeparator();
270 action = menu->addAction( i18n("Unify Outputs"), screen, SLOT(slotUnifyOutputs(bool)) );
271 action->setCheckable(true);
272 action->setChecked(screen->outputsUnified());
275 else
276 #endif
277 populateLegacyMenu(menu);
280 void KRandRSystemTray::populateLegacyMenu(KMenu* menu)
282 menu->addTitle(SmallIcon("view-fullscreen"), i18n("Screen Size"));
284 LegacyRandRScreen *screen = m_display->currentLegacyScreen();
285 Q_ASSERT(screen);
287 // add sizes
288 QActionGroup *screenSizeGroup = populateSizes(menu, RandR::sortSizes(screen->pixelSizes()), screen->currentPixelSize());
289 connect(screenSizeGroup, SIGNAL(triggered(QAction*)), SLOT(slotResolutionChanged(QAction*)));
291 // Don't display the rotation options if there is no point (ie. none are supported)
292 // XFree86 4.3 does not include rotation support.
293 if (screen->rotations() != RandR::Rotate0)
295 menu->addTitle(SmallIcon("view-refresh"), i18n("Orientation"));
297 QActionGroup *rotationGroup = populateRotations(menu, screen->rotations(), screen->rotation());
298 connect(rotationGroup, SIGNAL(triggered(QAction*)), SLOT(slotOrientationChanged(QAction*)));
301 RateList rr = screen->refreshRates(screen->proposedSize());
302 if (rr.count())
304 menu->addTitle(SmallIcon("clock"), i18n("Refresh Rate"));
306 QActionGroup *rateGroup = populateRates(menu, rr, screen->refreshRate());
307 connect(rateGroup, SIGNAL(triggered(QAction*)), SLOT(slotRefreshRateChanged(QAction*)));
311 QActionGroup *KRandRSystemTray::populateRotations(KMenu *menu, int rotations, int rotation)
313 QAction *action;
314 QActionGroup *rotateGroup = new QActionGroup(menu);
317 for (int i = 0; i < 6; i++)
319 if ((1 << i) & rotations)
321 action = menu->addAction(QIcon(RandR::rotationIcon(1 << i, rotation)),
322 RandR::rotationName(1 << i));
324 action->setData(1 << i);
325 if (rotation & (1 << i))
327 QFont font = action->font();
328 font.setBold(true);
329 action->setFont(font);
331 rotateGroup->addAction(action);
334 return rotateGroup;
337 QActionGroup *KRandRSystemTray::populateSizes(KMenu *menu, const SizeList &sizes, const QSize &size)
339 QAction *action;
340 QActionGroup *sizeGroup = new QActionGroup(menu);
341 for (int i = 0; i < sizes.count(); ++i)
343 QSize s = sizes[i];
344 action = menu->addAction(QString("%1 x %2").arg(s.width()).arg(s.height()));
345 action->setData(s);
346 if (s == size)
348 QFont font = action->font();
349 font.setBold(true);
350 action->setFont(font);
352 sizeGroup->addAction(action);
354 return sizeGroup;
357 QActionGroup *KRandRSystemTray::populateRates(KMenu *menu, const RateList &rates, float rate)
359 QAction *action;
360 QActionGroup *rateGroup = new QActionGroup(menu);
362 foreach(float r, rates)
364 action = menu->addAction(ki18n("%1 Hz").subs(r, 0, 'f', 1).toString());
365 action->setData(r);
366 if (r == rate)
368 QFont f = action->font();
369 f.setBold(true);
370 action->setFont(f);
372 rateGroup->addAction(action);
374 return rateGroup;
377 void KRandRSystemTray::slotResolutionChanged(QAction *action)
379 LegacyRandRScreen *screen = m_display->currentLegacyScreen();
380 Q_ASSERT(screen);
382 QSize s = action->data().toSize();
383 int index = 0;
384 SizeList pixelSizes = screen->pixelSizes();
385 for (int i = 0; i < pixelSizes.count(); ++i)
386 if (pixelSizes[i] == s)
388 index = i;
389 break;
392 if (screen->size() == index)
393 return;
395 screen->proposeSize(index);
397 screen->proposeRefreshRate(-1);
399 if (screen->applyProposedAndConfirm())
401 KConfig config("krandrrc");
402 if (m_display->syncTrayApp(config))
403 screen->save(config);
407 void KRandRSystemTray::slotOrientationChanged(QAction *action)
409 LegacyRandRScreen *screen = m_display->currentLegacyScreen();
410 Q_ASSERT(screen);
412 int propose = screen->rotation();
413 int rotate = action->data().toInt();
415 if (rotate & RandR::RotateMask)
416 propose &= RandR::ReflectMask;
418 propose ^= rotate;
420 if (screen->rotation() == propose)
421 return;
423 screen->proposeRotation(propose);
425 if (screen->applyProposedAndConfirm())
427 KConfig config("krandrrc");
428 if (m_display->syncTrayApp(config))
429 screen->save(config);
433 void KRandRSystemTray::slotRefreshRateChanged(QAction *action)
435 LegacyRandRScreen *screen = m_display->currentLegacyScreen();
436 Q_ASSERT(screen);
438 int index = action->data().toInt();
440 if (screen->refreshRate() == index)
441 return;
443 screen->proposeRefreshRate(index);
445 if (screen->applyProposedAndConfirm())
447 KConfig config("krandrrc");
448 if (m_display->syncTrayApp(config))
449 screen->save(config);
453 void KRandRSystemTray::slotPrefs()
455 KCMultiDialog *kcm = new KCMultiDialog( parentWidget() );
456 kcm->setFaceType( KCMultiDialog::Plain );
457 kcm->setPlainCaption( i18n( "Configure Display" ) );
458 kcm->addModule( "display" );
459 kcm->exec();