1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <qsessionmanager.h>
41#include <qguiapplication.h>
42#include <qpa/qplatformsessionmanager.h>
43#include <qpa/qplatformintegration.h>
44
45#include <private/qobject_p.h>
46#include <private/qguiapplication_p.h>
47#include <private/qsessionmanager_p.h>
48
49#ifndef QT_NO_SESSIONMANAGER
50
51QT_BEGIN_NAMESPACE
52
53/*!
54 \class QSessionManager
55 \brief The QSessionManager class provides access to the session manager.
56
57 \inmodule QtGui
58
59 A session manager in a desktop environment (in which Qt GUI applications
60 live) keeps track of a session, which is a group of running applications,
61 each of which has a particular state. The state of an application contains
62 (most notably) the documents the application has open and the position and
63 size of its windows.
64
65 The session manager is used to save the session, e.g., when the machine is
66 shut down, and to restore a session, e.g., when the machine is started up.
67 We recommend that you use QSettings to save an application's settings,
68 for example, window positions, recently used files, etc. When the
69 application is restarted by the session manager, you can restore the
70 settings.
71
72 QSessionManager provides an interface between the application and the
73 platform's session manager. In Qt, session management requests for action
74 are handled by the two signals QGuiApplication::commitDataRequest() and
75 QGuiApplication::saveStateRequest(). Both provide a reference to a
76 QSessionManager object as argument. The session manager can only be
77 accessed in slots invoked by these signals.
78
79 \warning If you use QSessionManager, you should disable fallback session
80 management: QGuiApplication::setFallbackSessionManagementEnabled().
81
82 No user interaction is possible \e unless the application gets explicit
83 permission from the session manager. You ask for permission by calling
84 allowsInteraction() or, if it is really urgent, allowsErrorInteraction().
85 Qt does not enforce this, but the session manager may.
86
87 You can try to abort the shutdown process by calling cancel().
88
89 For sophisticated session managers provided on Unix/X11, QSessionManager
90 offers further possibilities to fine-tune an application's session
91 management behavior: setRestartCommand(), setDiscardCommand(),
92 setRestartHint(), setProperty(), requestPhase2(). See the respective
93 function descriptions for further details.
94
95 \sa QGuiApplication, {Session Management}
96*/
97
98
99/*! \enum QSessionManager::RestartHint
100
101 This enum type defines the circumstances under which this application wants
102 to be restarted by the session manager. The current values are:
103
104 \value RestartIfRunning If the application is still running when the
105 session is shut down, it wants to be restarted
106 at the start of the next session.
107
108 \value RestartAnyway The application wants to be started at the
109 start of the next session, no matter what.
110 (This is useful for utilities that run just
111 after startup and then quit.)
112
113 \value RestartImmediately The application wants to be started immediately
114 whenever it is not running.
115
116 \value RestartNever The application does not want to be restarted
117 automatically.
118
119 The default hint is \c RestartIfRunning.
120*/
121
122QSessionManagerPrivate::QSessionManagerPrivate(const QString &id,
123 const QString &key)
124 : QObjectPrivate()
125{
126 if (qApp->testAttribute(Qt::AA_DisableSessionManager)) {
127 platformSessionManager = new QPlatformSessionManager(id, key);
128 } else {
129 platformSessionManager = QGuiApplicationPrivate::platformIntegration()->createPlatformSessionManager(id, key);
130 }
131 Q_ASSERT_X(platformSessionManager, "Platform session management",
132 "No platform session management, should use the default implementation");
133}
134
135QSessionManagerPrivate::~QSessionManagerPrivate()
136{
137 delete platformSessionManager;
138 platformSessionManager = 0;
139}
140
141QSessionManager::QSessionManager(QGuiApplication *app, QString &id, QString &key)
142 : QObject(*(new QSessionManagerPrivate(id, key)), app)
143{
144}
145
146QSessionManager::~QSessionManager()
147{
148}
149
150/*!
151 Returns the identifier of the current session.
152
153 If the application has been restored from an earlier session, this
154 identifier is the same as it was in the earlier session.
155
156 \sa sessionKey(), QGuiApplication::sessionId()
157*/
158QString QSessionManager::sessionId() const
159{
160 Q_D(const QSessionManager);
161 return d->platformSessionManager->sessionId();
162}
163
164/*!
165 \fn QString QSessionManager::sessionKey() const
166
167 Returns the session key in the current session.
168
169 If the application has been restored from an earlier session, this key is
170 the same as it was when the previous session ended.
171
172 The session key changes with every call of commitData() or saveState().
173
174 \sa sessionId(), QGuiApplication::sessionKey()
175*/
176QString QSessionManager::sessionKey() const
177{
178 Q_D(const QSessionManager);
179 return d->platformSessionManager->sessionKey();
180}
181
182
183/*!
184 Asks the session manager for permission to interact with the user. Returns
185 true if interaction is permitted; otherwise returns \c false.
186
187 The rationale behind this mechanism is to make it possible to synchronize
188 user interaction during a shutdown. Advanced session managers may ask all
189 applications simultaneously to commit their data, resulting in a much
190 faster shutdown.
191
192 When the interaction is completed we strongly recommend releasing the user
193 interaction semaphore with a call to release(). This way, other
194 applications may get the chance to interact with the user while your
195 application is still busy saving data. (The semaphore is implicitly
196 released when the application exits.)
197
198 If the user decides to cancel the shutdown process during the interaction
199 phase, you must tell the session manager that this has happened by calling
200 cancel().
201
202 Here's an example of how an application's QGuiApplication::commitDataRequest()
203 might be implemented:
204
205 \snippet code/src_gui_kernel_qguiapplication.cpp 1
206
207 If an error occurred within the application while saving its data, you may
208 want to try allowsErrorInteraction() instead.
209
210 \sa QGuiApplication::commitDataRequest(), release(), cancel()
211*/
212bool QSessionManager::allowsInteraction()
213{
214 Q_D(QSessionManager);
215 return d->platformSessionManager->allowsInteraction();
216}
217
218/*!
219 Returns \c true if error interaction is permitted; otherwise returns \c false.
220
221 This is similar to allowsInteraction(), but also enables the application to
222 tell the user about any errors that occur. Session managers may give error
223 interaction requests higher priority, which means that it is more likely
224 that an error interaction is permitted. However, you are still not
225 guaranteed that the session manager will allow interaction.
226
227 \sa allowsInteraction(), release(), cancel()
228*/
229bool QSessionManager::allowsErrorInteraction()
230{
231 Q_D(QSessionManager);
232 return d->platformSessionManager->allowsErrorInteraction();
233}
234
235/*!
236 Releases the session manager's interaction semaphore after an interaction
237 phase.
238
239 \sa allowsInteraction(), allowsErrorInteraction()
240*/
241void QSessionManager::release()
242{
243 Q_D(QSessionManager);
244 d->platformSessionManager->release();
245}
246
247/*!
248 Tells the session manager to cancel the shutdown process. Applications
249 should not call this function without asking the user first.
250
251 \sa allowsInteraction(), allowsErrorInteraction()
252*/
253void QSessionManager::cancel()
254{
255 Q_D(QSessionManager);
256 d->platformSessionManager->cancel();
257}
258
259/*!
260 Sets the application's restart hint to \a hint. On application startup, the
261 hint is set to \c RestartIfRunning.
262
263 \note These flags are only hints, a session manager may or may not respect
264 them.
265
266 We recommend setting the restart hint in QGuiApplication::saveStateRequest()
267 because most session managers perform a checkpoint shortly after an
268 application's
269 startup.
270
271 \sa restartHint()
272*/
273void QSessionManager::setRestartHint(QSessionManager::RestartHint hint)
274{
275 Q_D(QSessionManager);
276 d->platformSessionManager->setRestartHint(hint);
277}
278
279/*!
280 \fn QSessionManager::RestartHint QSessionManager::restartHint() const
281
282 Returns the application's current restart hint. The default is
283 \c RestartIfRunning.
284
285 \sa setRestartHint()
286*/
287QSessionManager::RestartHint QSessionManager::restartHint() const
288{
289 Q_D(const QSessionManager);
290 return d->platformSessionManager->restartHint();
291}
292
293/*!
294 If the session manager is capable of restoring sessions it will execute
295 \a command in order to restore the application. The command defaults to
296
297 \snippet code/src_gui_kernel_qguiapplication.cpp 2
298
299 The \c -session option is mandatory; otherwise QGuiApplication cannot
300 tell whether it has been restored or what the current session identifier
301 is.
302 See QGuiApplication::isSessionRestored() and
303 QGuiApplication::sessionId() for details.
304
305 If your application is very simple, it may be possible to store the entire
306 application state in additional command line options. This is usually a
307 very bad idea because command lines are often limited to a few hundred
308 bytes. Instead, use QSettings, temporary files, or a database for this
309 purpose. By marking the data with the unique sessionId(), you will be able
310 to restore the application in a future session.
311
312 \sa restartCommand(), setDiscardCommand(), setRestartHint()
313*/
314void QSessionManager::setRestartCommand(const QStringList &command)
315{
316 Q_D(QSessionManager);
317 d->platformSessionManager->setRestartCommand(command);
318}
319
320/*!
321 Returns the currently set restart command.
322
323 To iterate over the list, you can use the \l foreach pseudo-keyword:
324
325 \snippet code/src_gui_kernel_qguiapplication.cpp 3
326
327 \sa setRestartCommand(), restartHint()
328*/
329QStringList QSessionManager::restartCommand() const
330{
331 Q_D(const QSessionManager);
332 return d->platformSessionManager->restartCommand();
333}
334
335/*!
336 Sets the discard command to the given \a command.
337
338 \sa discardCommand(), setRestartCommand()
339*/
340void QSessionManager::setDiscardCommand(const QStringList &command)
341{
342 Q_D(QSessionManager);
343 d->platformSessionManager->setDiscardCommand(command);
344}
345
346/*!
347 Returns the currently set discard command.
348
349 To iterate over the list, you can use the \l foreach pseudo-keyword:
350
351 \snippet code/src_gui_kernel_qguiapplication.cpp 4
352
353 \sa setDiscardCommand(), restartCommand(), setRestartCommand()
354*/
355QStringList QSessionManager::discardCommand() const
356{
357 Q_D(const QSessionManager);
358 return d->platformSessionManager->discardCommand();
359}
360
361/*!
362 \overload
363
364 Low-level write access to the application's identification and state
365 records are kept in the session manager.
366
367 The property called \a name has its value set to the string \a value.
368*/
369void QSessionManager::setManagerProperty(const QString &name,
370 const QString &value)
371{
372 Q_D(QSessionManager);
373 d->platformSessionManager->setManagerProperty(name, value);
374}
375
376/*!
377 Low-level write access to the application's identification and state record
378 are kept in the session manager.
379
380 The property called \a name has its value set to the string list \a value.
381*/
382void QSessionManager::setManagerProperty(const QString &name,
383 const QStringList &value)
384{
385 Q_D(QSessionManager);
386 d->platformSessionManager->setManagerProperty(name, value);
387}
388
389/*!
390 Returns \c true if the session manager is currently performing a second
391 session management phase; otherwise returns \c false.
392
393 \sa requestPhase2()
394*/
395bool QSessionManager::isPhase2() const
396{
397 Q_D(const QSessionManager);
398 return d->platformSessionManager->isPhase2();
399}
400
401/*!
402 Requests a second session management phase for the application. The
403 application may then return immediately from the
404 QGuiApplication::commitDataRequest() or QApplication::saveStateRequest()
405 function, and they will be called again once most or all other
406 applications have finished their session management.
407
408 The two phases are useful for applications such as the X11 window manager
409 that need to store information about another application's windows and
410 therefore have to wait until these applications have completed their
411 respective session management tasks.
412
413 \note If another application has requested a second phase it may get called
414 before, simultaneously with, or after your application's second phase.
415
416 \sa isPhase2()
417*/
418void QSessionManager::requestPhase2()
419{
420 Q_D(QSessionManager);
421 d->platformSessionManager->requestPhase2();
422}
423
424QT_END_NAMESPACE
425
426#endif // QT_NO_SESSIONMANAGER
427