1/*****************************************************************
2ksmserver - the KDE session management server
3
4Copyright 2000 Matthias Ettrich <ettrich@kde.org>
5Copyright 2007 Urs Wolfer <uwolfer @ kde.org>
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24******************************************************************/
25
26#include "shutdowndlg.h"
27#include "plasma/framesvg.h"
28#include "plasma/theme.h"
29
30#include <QApplication>
31#include <QDesktopWidget>
32#include <QTimer>
33#include <QFile>
34#include <QtDBus/QDBusConnection>
35#include <QtDBus/QDBusMessage>
36#include <QtDBus/QDBusPendingCall>
37#include <QDeclarativeView>
38#include <QDeclarativeContext>
39#include <QDeclarativeEngine>
40#include <QDeclarativePropertyMap>
41
42#include <kdialog.h>
43#include <kiconloader.h>
44#include <klocale.h>
45#include <kuser.h>
46#include <Solid/PowerManagement>
47#include <kwindowsystem.h>
48#include <netwm.h>
49#include <KStandardDirs>
50#include <kdeclarative.h>
51
52#include <stdio.h>
53#include <kxerrorhandler.h>
54
55#include <kworkspace/kdisplaymanager.h>
56
57#include <config-workspace.h>
58
59#include "logouteffect.h"
60#include "shutdowndlg.moc"
61
62#include <kjob.h>
63
64#define FONTCOLOR "#bfbfbf"
65
66KSMShutdownFeedback * KSMShutdownFeedback::s_pSelf = 0L;
67
68KSMShutdownFeedback::KSMShutdownFeedback()
69 : QWidget( 0L, Qt::Popup ),
70 m_currentY( 0 ), initialized( false )
71{
72 setObjectName( "feedbackwidget" );
73 setAttribute( Qt::WA_NoSystemBackground );
74 setAttribute( Qt::WA_PaintOnScreen );
75 setGeometry( QApplication::desktop()->geometry() );
76 m_pixmap = QPixmap( size() );
77 QTimer::singleShot( 10, this, SLOT(slotPaintEffect()) );
78}
79
80
81void KSMShutdownFeedback::paintEvent( QPaintEvent* )
82{
83 if ( !initialized )
84 return;
85
86 QPainter painter( this );
87 painter.setCompositionMode( QPainter::CompositionMode_Source );
88 painter.drawPixmap( 0, 0, m_pixmap );
89}
90
91void KSMShutdownFeedback::slotPaintEffect()
92{
93 effect = LogoutEffect::create(this, &m_pixmap);
94 connect(effect, SIGNAL(initialized()),
95 this, SLOT (slotPaintEffectInitialized()));
96
97 effect->start();
98}
99
100void KSMShutdownFeedback::slotPaintEffectInitialized()
101{
102 initialized = true;
103}
104
105void KSMShutdownFeedback::start()
106{
107 if( KWindowSystem::compositingActive()) {
108 // HACK do properly
109 Display* dpy = QX11Info::display();
110 char net_wm_cm_name[ 100 ];
111 sprintf( net_wm_cm_name, "_NET_WM_CM_S%d", DefaultScreen( dpy ));
112 Atom net_wm_cm = XInternAtom( dpy, net_wm_cm_name, False );
113 Window sel = XGetSelectionOwner( dpy, net_wm_cm );
114 Atom hack = XInternAtom( dpy, "_KWIN_LOGOUT_EFFECT", False );
115 bool wmsupport = false;
116 if( sel != None ) {
117 KXErrorHandler handler;
118 int cnt;
119 Atom* props = XListProperties( dpy, sel, &cnt );
120 if( !handler.error( false ) && props != NULL && qFind( props, props + cnt, hack ) != props + cnt )
121 wmsupport = true;
122 if( props != NULL )
123 XFree( props );
124 }
125 if( wmsupport ) {
126 // Announce that the user MAY be logging out (Intended for the compositor)
127 Atom announce = XInternAtom(dpy, "_KDE_LOGGING_OUT", False);
128 unsigned char dummy = 0;
129 XChangeProperty(dpy, QX11Info::appRootWindow(), announce, announce, 8, PropModeReplace,
130 &dummy, 1);
131
132 // Don't show our own effect
133 return;
134 }
135 }
136 s_pSelf = new KSMShutdownFeedback();
137 s_pSelf->show();
138}
139
140void KSMShutdownFeedback::stop()
141{
142 delete s_pSelf;
143 s_pSelf = NULL;
144}
145
146void KSMShutdownFeedback::logoutCanceled()
147{
148 if( KWindowSystem::compositingActive()) {
149 // We are no longer logging out, announce (Intended for the compositor)
150 Display* dpy = QX11Info::display();
151 Atom announce = XInternAtom(dpy, "_KDE_LOGGING_OUT", False);
152 XDeleteProperty(QX11Info::display(), QX11Info::appRootWindow(), announce);
153 }
154}
155
156////////////
157
158Q_DECLARE_METATYPE(Solid::PowerManagement::SleepState)
159
160KSMShutdownDlg::KSMShutdownDlg( QWidget* parent,
161 bool maysd, bool choose, KWorkSpace::ShutdownType sdtype,
162 const QString& theme)
163 : QDialog( parent, Qt::Popup ) //krazy:exclude=qclasses
164 // this is a WType_Popup on purpose. Do not change that! Not
165 // having a popup here has severe side effects.
166{
167 winId(); // workaround for Qt4.3 setWindowRole() assert
168 setWindowRole( "logoutdialog" );
169//#if !(QT_VERSION >= QT_VERSION_CHECK(4, 3, 3) || defined(QT_KDE_QT_COPY))
170// Qt doesn't set this on unmanaged windows
171 QByteArray appName = qAppName().toLatin1();
172 XClassHint class_hint;
173 class_hint.res_name = appName.data(); // application name
174 class_hint.res_class = const_cast<char *>(QX11Info::appClass()); // application class
175 XSetWMProperties( QX11Info::display(), winId(), NULL, NULL, NULL, 0, NULL, NULL, &class_hint );
176 XChangeProperty( QX11Info::display(), winId(),
177 XInternAtom( QX11Info::display(), "WM_WINDOW_ROLE", False ), XA_STRING, 8, PropModeReplace,
178 (unsigned char *)"logoutdialog", strlen( "logoutdialog" ));
179
180//#endif
181
182 KDialog::centerOnScreen(this, -3);
183
184 //kDebug() << "Creating QML view";
185 m_view = new QDeclarativeView(this);
186 QDeclarativeContext *context = m_view->rootContext();
187 context->setContextProperty("maysd", maysd);
188 context->setContextProperty("choose", choose);
189 context->setContextProperty("sdtype", sdtype);
190
191 QDeclarativePropertyMap *mapShutdownType = new QDeclarativePropertyMap(this);
192 mapShutdownType->insert("ShutdownTypeDefault", QVariant::fromValue((int)KWorkSpace::ShutdownTypeDefault));
193 mapShutdownType->insert("ShutdownTypeNone", QVariant::fromValue((int)KWorkSpace::ShutdownTypeNone));
194 mapShutdownType->insert("ShutdownTypeReboot", QVariant::fromValue((int)KWorkSpace::ShutdownTypeReboot));
195 mapShutdownType->insert("ShutdownTypeHalt", QVariant::fromValue((int)KWorkSpace::ShutdownTypeHalt));
196 mapShutdownType->insert("ShutdownTypeLogout", QVariant::fromValue((int)KWorkSpace::ShutdownTypeLogout));
197 context->setContextProperty("ShutdownType", mapShutdownType);
198
199 QDeclarativePropertyMap *mapSpdMethods = new QDeclarativePropertyMap(this);
200 QSet<Solid::PowerManagement::SleepState> spdMethods = Solid::PowerManagement::supportedSleepStates();
201 mapSpdMethods->insert("StandbyState", QVariant::fromValue(spdMethods.contains(Solid::PowerManagement::StandbyState)));
202 mapSpdMethods->insert("SuspendState", QVariant::fromValue(spdMethods.contains(Solid::PowerManagement::SuspendState)));
203 mapSpdMethods->insert("HibernateState", QVariant::fromValue(spdMethods.contains(Solid::PowerManagement::HibernateState)));
204 context->setContextProperty("spdMethods", mapSpdMethods);
205
206 QString bootManager = KConfig(KDE_CONFDIR "/kdm/kdmrc", KConfig::SimpleConfig).group("Shutdown").readEntry("BootManager", "None");
207 context->setContextProperty("bootManager", bootManager);
208
209 QStringList options;
210 int def, cur;
211 if ( KDisplayManager().bootOptions( rebootOptions, def, cur ) ) {
212 if ( cur > -1 ) {
213 def = cur;
214 }
215 }
216 QDeclarativePropertyMap *rebootOptionsMap = new QDeclarativePropertyMap(this);
217 rebootOptionsMap->insert("options", QVariant::fromValue(rebootOptions));
218 rebootOptionsMap->insert("default", QVariant::fromValue(def));
219 context->setContextProperty("rebootOptions", rebootOptionsMap);
220
221 setModal( true );
222
223 // window stuff
224 m_view->setFrameShape(QFrame::NoFrame);
225 m_view->setWindowFlags(Qt::X11BypassWindowManagerHint);
226 m_view->setAttribute(Qt::WA_TranslucentBackground);
227 setAttribute(Qt::WA_TranslucentBackground);
228 setStyleSheet("background:transparent;");
229 QPalette pal = m_view->palette();
230 pal.setColor(backgroundRole(), Qt::transparent);
231 m_view->setPalette(pal);
232 m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
233 m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
234 // engine stuff
235 KDeclarative kdeclarative;
236 kdeclarative.setDeclarativeEngine(m_view->engine());
237 kdeclarative.initialize();
238 kdeclarative.setupBindings();
239 m_view->installEventFilter(this);
240
241 QString fileName = KStandardDirs::locate("data", QString("ksmserver/themes/%1/main.qml").arg(theme));
242 if (QFile::exists(fileName)) {
243 //kDebug() << "Using QML theme" << fileName;
244 m_view->setSource(QUrl::fromLocalFile(fileName));
245 }
246 QGraphicsObject *rootObject = m_view->rootObject();
247 connect(rootObject, SIGNAL(logoutRequested()), SLOT(slotLogout()));
248 connect(rootObject, SIGNAL(haltRequested()), SLOT(slotHalt()));
249 connect(rootObject, SIGNAL(suspendRequested(int)), SLOT(slotSuspend(int)) );
250 connect(rootObject, SIGNAL(rebootRequested()), SLOT(slotReboot()));
251 connect(rootObject, SIGNAL(rebootRequested2(int)), SLOT(slotReboot(int)) );
252 connect(rootObject, SIGNAL(cancelRequested()), SLOT(reject()));
253 connect(rootObject, SIGNAL(lockScreenRequested()), SLOT(slotLockScreen()));
254 m_view->show();
255 m_view->setFocus();
256 adjustSize();
257}
258
259bool KSMShutdownDlg::eventFilter ( QObject * watched, QEvent * event )
260{
261 if (watched == m_view && event->type() == QEvent::Resize) {
262 adjustSize();
263 }
264 return QDialog::eventFilter(watched, event);
265}
266
267void KSMShutdownDlg::resizeEvent(QResizeEvent *e)
268{
269 QDialog::resizeEvent( e );
270
271 if( KWindowSystem::compositingActive()) {
272 clearMask();
273 } else {
274 setMask(m_view->mask());
275 }
276
277 KDialog::centerOnScreen(this, -3);
278}
279
280void KSMShutdownDlg::slotLogout()
281{
282 m_shutdownType = KWorkSpace::ShutdownTypeNone;
283 accept();
284}
285
286void KSMShutdownDlg::slotReboot()
287{
288 // no boot option selected -> current
289 m_bootOption.clear();
290 m_shutdownType = KWorkSpace::ShutdownTypeReboot;
291 accept();
292}
293
294void KSMShutdownDlg::slotReboot(int opt)
295{
296 if (int(rebootOptions.size()) > opt)
297 m_bootOption = rebootOptions[opt];
298 m_shutdownType = KWorkSpace::ShutdownTypeReboot;
299 accept();
300}
301
302
303void KSMShutdownDlg::slotLockScreen()
304{
305 m_bootOption.clear();
306 QDBusMessage call = QDBusMessage::createMethodCall("org.kde.screensaver",
307 "/ScreenSaver",
308 "org.freedesktop.ScreenSaver",
309 "Lock");
310 QDBusConnection::sessionBus().asyncCall(call);
311 reject();
312}
313
314void KSMShutdownDlg::slotHalt()
315{
316 m_bootOption.clear();
317 m_shutdownType = KWorkSpace::ShutdownTypeHalt;
318 accept();
319}
320
321
322void KSMShutdownDlg::slotSuspend(int spdMethod)
323{
324 m_bootOption.clear();
325 switch (spdMethod) {
326 case Solid::PowerManagement::StandbyState:
327 case Solid::PowerManagement::SuspendState:
328 Solid::PowerManagement::requestSleep(Solid::PowerManagement::SuspendState, 0, 0);
329 break;
330 case Solid::PowerManagement::HibernateState:
331 Solid::PowerManagement::requestSleep(Solid::PowerManagement::HibernateState, 0, 0);
332 break;
333 }
334 reject();
335}
336
337bool KSMShutdownDlg::confirmShutdown(
338 bool maysd, bool choose, KWorkSpace::ShutdownType& sdtype, QString& bootOption,
339 const QString& theme)
340{
341 KSMShutdownDlg* l = new KSMShutdownDlg( 0,
342 //KSMShutdownFeedback::self(),
343 maysd, choose, sdtype, theme );
344 XClassHint classHint;
345 classHint.res_name = const_cast<char*>("ksmserver");
346 classHint.res_class = const_cast<char*>("ksmserver");
347
348 XSetClassHint(QX11Info::display(), l->winId(), &classHint);
349 bool result = l->exec();
350 sdtype = l->m_shutdownType;
351 bootOption = l->m_bootOption;
352
353 delete l;
354
355 return result;
356}
357