Add (and install) svg for the new krunner interface.
[kdebase/uwolfer.git] / workspace / ksmserver / shutdowndlg.cpp
blob5707b878576399ce2c8eafba7b3638cdfac650a0
1 /*****************************************************************
2 ksmserver - the KDE session management server
4 Copyright 2000 Matthias Ettrich <ettrich@kde.org>
5 Copyright 2007 Urs Wolfer <uwolfer @ kde.org>
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 ******************************************************************/
26 #include <config-workspace.h>
28 #include "shutdowndlg.h"
29 #include "plasma/svg.h"
31 #include <QBitmap>
32 #include <QDesktopWidget>
33 #include <QLabel>
34 #include <QPainter>
35 #include <QMenu>
36 #include <QTimer>
37 #include <QTimeLine>
38 #include <QPaintEvent>
39 #include <QVBoxLayout>
40 #include <QHBoxLayout>
42 #include <qimageblitz.h>
44 #include <KApplication>
45 #include <kdialog.h>
46 #include <kiconloader.h>
47 #include <klocale.h>
48 #include <kuser.h>
49 #include <solid/control/powermanager.h>
50 #include <kwindowsystem.h>
51 #include <netwm.h>
53 #include <stdio.h>
54 #include <kxerrorhandler.h>
56 #include <kdisplaymanager.h>
58 #include "shutdowndlg.moc"
60 #define FONTCOLOR "#bfbfbf"
62 KSMShutdownFeedback * KSMShutdownFeedback::s_pSelf = 0L;
64 KSMShutdownFeedback::KSMShutdownFeedback()
65 : QWidget( 0L, Qt::Popup ),
66 m_currentY( 0 )
68 setObjectName( "feedbackwidget" );
69 setAttribute( Qt::WA_NoSystemBackground );
70 setAttribute( Qt::WA_PaintOnScreen );
71 setGeometry( QApplication::desktop()->geometry() );
72 m_pixmap = QPixmap( size() );
73 m_pixmap.fill( Qt::transparent );
74 QTimer::singleShot( 10, this, SLOT( slotPaintEffect() ) );
78 void KSMShutdownFeedback::paintEvent( QPaintEvent* )
80 if ( m_currentY >= height() ) {
81 QPainter painter( this );
82 painter.drawPixmap( 0, 0, m_pixmap );
83 return;
86 QPainter painter( this );
87 painter.drawPixmap( 0, 0, m_pixmap, 0, 0, width(), m_currentY );
90 void KSMShutdownFeedback::slotPaintEffect()
92 if ( m_currentY >= height() )
93 return;
95 QImage image = QPixmap::grabWindow( QApplication::desktop()->winId(), 0, m_currentY, width(), 10 ).toImage();
96 Blitz::intensity( image, -0.4 );
97 Blitz::grayscale( image );
99 QPainter painter( &m_pixmap );
100 painter.drawImage( 0, m_currentY, image );
101 painter.end();
103 m_currentY += 10;
104 update( 0, 0, width(), m_currentY );
106 QTimer::singleShot( 5, this, SLOT( slotPaintEffect() ) );
109 void KSMShutdownFeedback::start()
111 if( KWindowSystem::compositingActive()) {
112 // HACK do properly
113 Display* dpy = QX11Info::display();
114 char net_wm_cm_name[ 100 ];
115 sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( dpy ));
116 Atom net_wm_cm = XInternAtom( dpy, net_wm_cm_name, False );
117 Window sel = XGetSelectionOwner( dpy, net_wm_cm );
118 Atom hack = XInternAtom( dpy, "_KWIN_LOGOUT_EFFECT", False );
119 bool wmsupport = false;
120 if( sel != None ) {
121 KXErrorHandler handler;
122 int cnt;
123 Atom* props = XListProperties( dpy, sel, &cnt );
124 if( !handler.error( false ) && props != NULL && qFind( props, props + cnt, hack ) != props + cnt )
125 wmsupport = true;
126 if( props != NULL )
127 XFree( props );
129 if( wmsupport )
130 return;
132 s_pSelf = new KSMShutdownFeedback();
133 s_pSelf->show();
136 void KSMShutdownFeedback::stop()
138 delete s_pSelf;
139 s_pSelf = NULL;
142 ////////////
144 KSMPushButton::KSMPushButton( const QString &text, QWidget *parent, bool smallButton )
145 : QPushButton( parent ), m_highlight( false ), m_text( text ), m_popupMenu(0), m_popupTimer(0),
146 m_glowOpacity( 0.0 ), m_smallButton( smallButton )
148 setAttribute(Qt::WA_Hover, true);
149 m_text = text;
150 init();
153 void KSMPushButton::init()
155 if (m_smallButton) {
156 setMinimumSize(88, 22);
157 setFixedHeight(22); // workaround: force correct height
158 } else {
159 setMinimumSize(165, 38);
162 connect( this, SIGNAL(pressed()), SLOT(slotPressed()) );
163 connect( this, SIGNAL(released()), SLOT(slotReleased()) );
165 m_glowSvg = new Plasma::Svg("dialogs/shutdowndialog", this);
166 connect( m_glowSvg, SIGNAL(repaintNeeded()), this, SLOT(update()) );
168 m_glowTimeLine = new QTimeLine( 150, this );
169 connect( m_glowTimeLine, SIGNAL(valueChanged(qreal)),
170 this, SLOT(animateGlow(qreal)) );
172 QFont fnt;
173 fnt.setPixelSize(12);
175 // Calculate the width of the text when splitted on two lines and
176 // properly resize the button.
177 if (QFontMetrics(fnt).width(m_text) > width() - 4 - (m_smallButton ? 16 : 32) ||
178 (2 * QFontMetrics(fnt).lineSpacing() > height() && !m_smallButton) ) {
179 int w, h;
180 int i = m_text.length()/2;
181 int fac = 1;
182 int diff = 1;
183 while( i && i < m_text.length() && m_text[i] != ' ' ) {
184 i = i + (diff * fac);
185 fac *= -1;
186 ++diff;
188 QString upper = m_text.left( i );
189 QString lower = m_text.right( m_text.length() - i );
191 w = qMax(QFontMetrics(fnt).width(upper) + 18 + (m_smallButton ? 16 : 32),
192 QFontMetrics(fnt).width(lower) + 18 + (m_smallButton ? 16 : 32));
193 w = qMax(w, width());
194 h = qMax(height(), ((upper.isEmpty() || lower.isEmpty()) ? 1 : 2) * QFontMetrics(fnt).lineSpacing());
195 if (w > width() || h > height()) {
196 setMinimumSize(w, h);
197 if (m_smallButton)
198 setFixedHeight(h);
199 updateGeometry();
204 void KSMPushButton::paintEvent( QPaintEvent * e )
206 QPainter p( this );
207 p.setClipRect( e->rect() );
208 p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
209 QPen pen;
210 QFont fnt;
211 fnt.setPixelSize(12);
212 p.setFont( fnt );
213 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
215 p.save();
217 if (m_glowOpacity > 0) {
218 p.setOpacity(m_glowOpacity); // fade in
219 m_glowSvg->paint(&p, QRect(0, 0, width(), height()), m_smallButton ? "button-small-hover" : "button-hover");
220 p.setOpacity(1.0 - m_glowOpacity); // fade normal background out
221 m_glowSvg->paint(&p, QRect(0, 0, width(), height()), m_smallButton ? "button-small-normal" : "button-normal");
222 p.setOpacity(1.0);
223 } else {
224 m_glowSvg->resize();
225 m_glowSvg->paint(&p, QRect(0, 0, width(), height()), m_smallButton ? "button-small-normal" : "button-normal");
228 p.restore();
230 p.setRenderHints( QPainter::Antialiasing, false);
231 p.drawPixmap(width() - (m_smallButton ? 16 : 32) - 4, height() / 2 - (m_smallButton ? 8 : 16), m_pixmap);
233 p.save();
234 p.setPen(QPen(QColor(FONTCOLOR)));
235 p.drawText(10, 0, width() - (m_smallButton ? 16 : 32) - 8, height(),
236 Qt::AlignVCenter | Qt::AlignLeft | Qt::TextWordWrap | Qt::TextShowMnemonic, m_text);
237 p.restore();
239 if( m_popupMenu ) {
240 p.save();
241 p.setBrush(QColor(FONTCOLOR));
242 pen.setColor(QColor(FONTCOLOR));
243 p.setPen( pen );
244 QPoint points[3] = {
245 QPoint(width() - 10 - 34, height() - 7),
246 QPoint(width() - 4 - 34, height() - 7),
247 QPoint(width() - 7 - 34, height() - 4) };
248 p.drawPolygon(points, 3); // TODO: use QStyle
249 p.restore();
253 void KSMPushButton::resizeEvent(QResizeEvent *e)
255 m_glowSvg->resize( e->size() );
256 QPushButton::resizeEvent( e );
259 void KSMPushButton::animateGlow( qreal value )
261 m_glowOpacity = value;
262 update();
265 void KSMPushButton::setPixmap( const QPixmap &p )
267 m_pixmap = p;
268 int size = m_smallButton ? 16 : 32;
269 if (m_pixmap.size().width() != size || m_pixmap.size().height() != size)
270 m_pixmap = m_pixmap.scaled(size, size);
271 update();
274 void KSMPushButton::setPopupMenu( QMenu *m )
276 m_popupMenu = m;
277 if( !m_popupTimer ) {
278 m_popupTimer = new QTimer( this );
279 connect( m_popupTimer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
283 void KSMPushButton::slotPressed()
285 if( m_popupTimer )
286 m_popupTimer->start( QApplication::startDragTime() );
289 void KSMPushButton::slotReleased()
291 if( m_popupTimer )
292 m_popupTimer->stop();
295 void KSMPushButton::slotTimeout()
297 m_popupTimer->stop();
298 if( m_popupMenu ) {
299 m_popupMenu->popup( mapToGlobal(rect().bottomLeft()) );
300 m_highlight = false;
301 update();
305 bool KSMPushButton::event( QEvent *e )
307 if (e->type() == QEvent::HoverEnter || e->type() == QEvent::FocusIn)
309 if (m_glowOpacity > 0) // already hovered
310 return true;
311 m_highlight = true;
312 m_glowTimeLine->setDirection( QTimeLine::Forward );
313 if (m_glowTimeLine->state() == QTimeLine::Running)
314 m_glowTimeLine->stop();
315 m_glowTimeLine->start();
316 update();
317 return true;
319 else if (e->type() == QEvent::HoverLeave || e->type() == QEvent::FocusOut)
321 if (hasFocus())
322 return true;
323 m_highlight = false;
324 m_glowTimeLine->setDirection( QTimeLine::Backward );
325 if (m_glowTimeLine->state() == QTimeLine::Running)
326 m_glowTimeLine->stop();
327 m_glowTimeLine->start();
328 update();
329 return true;
331 else
332 return QPushButton::event( e );
335 //////
337 Q_DECLARE_METATYPE(Solid::Control::PowerManager::SuspendMethod)
339 KSMShutdownDlg::KSMShutdownDlg( QWidget* parent,
340 bool maysd, KWorkSpace::ShutdownType sdtype )
341 : QDialog( parent, Qt::Popup )
342 // this is a WType_Popup on purpose. Do not change that! Not
343 // having a popup here has severe side effects.
345 winId(); // workaround for Qt4.3 setWindowRole() assert
346 setWindowRole( "logoutdialog" );
347 //#if !(QT_VERSION >= QT_VERSION_CHECK(4, 3, 3) || defined(QT_KDE_QT_COPY))
348 // Qt doesn't set this on unmanaged windows
349 QByteArray appName = qAppName().toLatin1();
350 XClassHint class_hint;
351 class_hint.res_name = appName.data(); // application name
352 class_hint.res_class = const_cast<char *>(QX11Info::appClass()); // application class
353 XSetWMProperties( QX11Info::display(), winId(), NULL, NULL, NULL, NULL, NULL, NULL, &class_hint );
354 XChangeProperty( QX11Info::display(), winId(),
355 XInternAtom( QX11Info::display(), "WM_WINDOW_ROLE", False ), XA_STRING, 8, PropModeReplace,
356 (unsigned char *)"logoutdialog", strlen( "logoutdialog" ));
358 //#endif
359 m_svg = new Plasma::Svg("dialogs/shutdowndialog", this);
360 connect( m_svg, SIGNAL(repaintNeeded()), this, SLOT(update()) );
361 setModal( true );
362 resize(400, 220);
363 KDialog::centerOnScreen(this);
365 QVBoxLayout *mainLayout = new QVBoxLayout();
367 mainLayout->setContentsMargins(9, 9, 12, 7);
368 QVBoxLayout *buttonLayout = new QVBoxLayout();
369 buttonLayout->addStretch();
370 QHBoxLayout *buttonMainLayout = new QHBoxLayout();
371 buttonMainLayout->addStretch();
372 buttonMainLayout->addLayout(buttonLayout);
374 QHBoxLayout *topLayout = new QHBoxLayout();
376 QHBoxLayout *bottomLayout = new QHBoxLayout();
378 QFont fnt;
379 fnt.setPixelSize(16);
381 QLabel *versionLabel = new QLabel(this);
383 int vmajor = KDE_VERSION_MAJOR;
384 int vminor = KDE_VERSION_MINOR;
385 int vbugfix = KDE_VERSION_RELEASE;
387 QString vcomposed;
388 if (vbugfix > 0) {
389 // Placeholders tagged <numid> to avoid treatment as amounts.
390 vcomposed = i18nc("@label In corner of the logout dialog",
391 "KDE <numid>%1.%2.%3</numid>", vmajor, vminor, vbugfix);
393 else {
394 vcomposed = i18nc("@label In corner of the logout dialog",
395 "KDE <numid>%1.%2</numid>", vmajor, vminor);
397 versionLabel->setText("<font color='" + QString(FONTCOLOR) + "'>" + vcomposed + "</font>");
398 versionLabel->setFont(fnt);
400 KUser userInformation;
401 QString logoutMsg;
402 QString userName = userInformation.property( KUser::FullName ).toString();
403 QString loginName = userInformation.loginName();
405 if (userName.isEmpty()) {
406 logoutMsg = i18n( "End Session for %1", loginName );
407 } else {
408 logoutMsg = i18n( "End Session for %1 (%2)", userName, loginName );
411 QLabel *logoutMessageLabel = new QLabel(this);
412 // FIXME Made the color picked from the user's one
413 logoutMessageLabel->setText("<font color='" + QString(FONTCOLOR) + "'>" + logoutMsg + "</font>");
414 logoutMessageLabel->setAlignment(Qt::AlignRight);
415 fnt.setPixelSize(12);
416 logoutMessageLabel->setFont(fnt);
417 logoutMessageLabel->setWordWrap(true);
419 topLayout->addWidget(versionLabel, 0, Qt::AlignTop); // correct possition if logoutMessageLabel has multiple lines
420 topLayout->addWidget(logoutMessageLabel, 1, Qt::AlignBottom);
422 KSMPushButton* btnLogout = new KSMPushButton( i18n("Logout"), this );
423 btnLogout->setPixmap(KIconLoader::global()->loadIcon("system-log-out", KIconLoader::NoGroup, 32));
424 btnLogout->setFocus();
425 connect(btnLogout, SIGNAL(clicked()), SLOT(slotLogout()));
426 buttonLayout->addWidget(btnLogout);
427 buttonLayout->addStretch();
429 if (maysd) {
430 // Shutdown
431 KSMPushButton* btnHalt = new KSMPushButton( i18n("Turn Off Computer"), this );
432 btnHalt->setPixmap(KIconLoader::global()->loadIcon("system-shutdown", KIconLoader::NoGroup, 32));
433 buttonLayout->addWidget(btnHalt);
434 buttonLayout->addStretch();
435 connect(btnHalt, SIGNAL(clicked()), SLOT(slotHalt()));
436 if ( sdtype == KWorkSpace::ShutdownTypeHalt )
437 btnHalt->setFocus();
439 QMenu *shutdownMenu = new QMenu( btnHalt );
440 QActionGroup* spdActionGroup = new QActionGroup(shutdownMenu);
441 connect( spdActionGroup, SIGNAL(triggered(QAction*)), SLOT(slotSuspend(QAction*)) );
442 btnHalt->setPopupMenu( shutdownMenu );
443 Solid::Control::PowerManager::SuspendMethods spdMethods = Solid::Control::PowerManager::supportedSuspendMethods();
444 if( spdMethods & Solid::Control::PowerManager::Standby ) {
445 QAction* action = new QAction(i18n("Standby"), spdActionGroup);
446 action->setData(QVariant::fromValue(Solid::Control::PowerManager::Standby));
448 if( spdMethods & Solid::Control::PowerManager::ToRam ) {
449 QAction* action = new QAction(i18n("Suspend to RAM"), spdActionGroup);
450 action->setData(QVariant::fromValue(Solid::Control::PowerManager::ToRam));
452 if( spdMethods & Solid::Control::PowerManager::ToDisk ) {
453 QAction* action = new QAction(i18n("Suspend to Disk"), spdActionGroup);
454 action->setData(QVariant::fromValue(Solid::Control::PowerManager::ToDisk));
456 shutdownMenu->addActions(spdActionGroup->actions());
458 // Reboot
459 KSMPushButton* btnReboot = new KSMPushButton( i18n("Restart Computer"), this );
460 btnReboot->setPixmap(KIconLoader::global()->loadIcon("system-restart", KIconLoader::NoGroup, 32));
461 connect(btnReboot, SIGNAL(clicked()), SLOT(slotReboot()));
462 buttonLayout->addWidget(btnReboot);
463 buttonLayout->addStretch();
464 if ( sdtype == KWorkSpace::ShutdownTypeReboot )
465 btnReboot->setFocus();
467 int def, cur;
468 if ( KDisplayManager().bootOptions( rebootOptions, def, cur ) ) {
469 if ( cur == -1 )
470 cur = def;
472 QMenu *rebootMenu = new QMenu( btnReboot );
473 QActionGroup* rebootActionGroup = new QActionGroup(rebootMenu);
474 connect( rebootActionGroup, SIGNAL(triggered(QAction*)), SLOT(slotReboot(QAction*)) );
475 btnReboot->setPopupMenu( rebootMenu );
477 int index = 0;
478 for (QStringList::ConstIterator it = rebootOptions.begin(); it != rebootOptions.end(); ++it, ++index) {
479 QString label = (*it);
480 label=label.replace('&',"&&");
481 QAction* action = new QAction(label, rebootActionGroup);
482 action->setData(index);
483 if (index == cur) {
484 action->setText( label + i18nc("current option in boot loader", " (current)") );
487 rebootMenu->addActions(rebootActionGroup->actions());
491 KSMPushButton* btnBack = new KSMPushButton(i18n("Cancel"), this, true);
492 btnBack->setPixmap(KIconLoader::global()->loadIcon( "dialog-cancel", KIconLoader::NoGroup, 16));
493 bottomLayout->addStretch();
494 bottomLayout->addWidget(btnBack);
495 connect(btnBack, SIGNAL(clicked()), SLOT(reject()));
497 mainLayout->addLayout(topLayout);
498 mainLayout->addLayout(buttonMainLayout);
499 mainLayout->addLayout(bottomLayout);
501 setLayout( mainLayout );
504 void KSMShutdownDlg::paintEvent(QPaintEvent *e)
506 Q_UNUSED(e);
507 QPainter p(this);
508 p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
509 m_svg->paint(&p, QRect(0, 0, width(), height()), "background");
512 void KSMShutdownDlg::resizeEvent(QResizeEvent *e)
514 QDialog::resizeEvent( e );
516 QBitmap mask(size());
517 mask.fill(Qt::color0);
519 QPainter p(&mask);
520 m_svg->resize(size());
521 m_svg->paint(&p, QRect(0, 0, width(), height()), "background");
522 setMask(mask);
525 void KSMShutdownDlg::slotLogout()
527 m_shutdownType = KWorkSpace::ShutdownTypeNone;
528 accept();
531 void KSMShutdownDlg::slotReboot()
533 // no boot option selected -> current
534 m_bootOption.clear();
535 m_shutdownType = KWorkSpace::ShutdownTypeReboot;
536 accept();
539 void KSMShutdownDlg::slotReboot(QAction* action)
541 int opt = action->data().toInt();
542 if (int(rebootOptions.size()) > opt)
543 m_bootOption = rebootOptions[opt];
544 m_shutdownType = KWorkSpace::ShutdownTypeReboot;
545 accept();
549 void KSMShutdownDlg::slotHalt()
551 m_bootOption.clear();
552 m_shutdownType = KWorkSpace::ShutdownTypeHalt;
553 accept();
557 void KSMShutdownDlg::slotSuspend(QAction* action)
559 m_bootOption.clear();
560 Solid::Control::PowerManager::SuspendMethod spdMethod = action->data().value<Solid::Control::PowerManager::SuspendMethod>();
561 Solid::Control::PowerManager::suspend( spdMethod );
562 reject();
565 bool KSMShutdownDlg::confirmShutdown( bool maysd, KWorkSpace::ShutdownType& sdtype, QString& bootOption )
567 KSMShutdownDlg* l = new KSMShutdownDlg( 0,
568 //KSMShutdownFeedback::self(),
569 maysd, sdtype );
570 bool result = l->exec();
571 sdtype = l->m_shutdownType;
572 bootOption = l->m_bootOption;
574 delete l;
576 return result;