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(m_menu
, SIGNAL(aboutToShow()), this, SLOT(slotPrepareMenu()));
61 void KRandRSystemTray::slotPrepareMenu()
67 if (!m_display
->isValid())
69 action
= m_menu
->addAction(i18n("Required X Extension Not Available"));
70 action
->setEnabled(false);
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);*/
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()));
98 m_display
->currentScreen()->loadSettings(true);
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;
133 // TODO: display config changed message
134 message
= "Screen config changed";
137 message
= m_display
->currentLegacyScreen()->changedMessage();
139 KRandrPassivePopup::message(
140 i18n("Screen configuration has changed"),
141 message
, SmallIcon("view-fullscreen"),
148 void KRandRSystemTray::populateMenu(KMenu
* menu
)
154 QActionGroup
*actionGroup
;
156 OutputMap outputs
= m_display
->currentScreen()->outputs();
157 if (outputs
.count() <= 0)
160 RandRScreen
*screen
= m_display
->currentScreen();
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();
171 // populate unified sizes
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();
192 actionGroup
= populateRotations(menu
, rotations
, rotation
);
193 connect(actionGroup
, SIGNAL(triggered(QAction
*)), screen
, SLOT(slotRotateUnified(QAction
*)));
199 if (screen
->connectedCount() != 1)
200 menu
->addTitle(SmallIcon("view-fullscreen"), i18n("Outputs"));
202 foreach(RandROutput
*output
, outputs
)
204 if (output
->isConnected())
207 if (screen
->connectedCount() == 1)
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();
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
*)));
252 RateList rates
= output
->refreshRates();
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());
277 populateLegacyMenu(menu
);
280 void KRandRSystemTray::populateLegacyMenu(KMenu
* menu
)
282 menu
->addTitle(SmallIcon("view-fullscreen"), i18n("Screen Size"));
284 LegacyRandRScreen
*screen
= m_display
->currentLegacyScreen();
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());
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
)
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();
329 action
->setFont(font
);
331 rotateGroup
->addAction(action
);
337 QActionGroup
*KRandRSystemTray::populateSizes(KMenu
*menu
, const SizeList
&sizes
, const QSize
&size
)
340 QActionGroup
*sizeGroup
= new QActionGroup(menu
);
341 for (int i
= 0; i
< sizes
.count(); ++i
)
344 action
= menu
->addAction(QString("%1 x %2").arg(s
.width()).arg(s
.height()));
348 QFont font
= action
->font();
350 action
->setFont(font
);
352 sizeGroup
->addAction(action
);
357 QActionGroup
*KRandRSystemTray::populateRates(KMenu
*menu
, const RateList
&rates
, float rate
)
360 QActionGroup
*rateGroup
= new QActionGroup(menu
);
362 foreach(float r
, rates
)
364 action
= menu
->addAction(ki18n("%1 Hz").subs(r
, 0, 'f', 1).toString());
368 QFont f
= action
->font();
372 rateGroup
->addAction(action
);
377 void KRandRSystemTray::slotResolutionChanged(QAction
*action
)
379 LegacyRandRScreen
*screen
= m_display
->currentLegacyScreen();
382 QSize s
= action
->data().toSize();
384 SizeList pixelSizes
= screen
->pixelSizes();
385 for (int i
= 0; i
< pixelSizes
.count(); ++i
)
386 if (pixelSizes
[i
] == s
)
392 if (screen
->size() == index
)
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();
412 int propose
= screen
->rotation();
413 int rotate
= action
->data().toInt();
415 if (rotate
& RandR::RotateMask
)
416 propose
&= RandR::ReflectMask
;
420 if (screen
->rotation() == propose
)
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();
438 int index
= action
->data().toInt();
440 if (screen
->refreshRate() == index
)
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" );