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 
51 QT_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 
QSessionManagerPrivate(const QString & id,const QString & key)122 QSessionManagerPrivate::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 
~QSessionManagerPrivate()135 QSessionManagerPrivate::~QSessionManagerPrivate()
136 {
137     delete platformSessionManager;
138     platformSessionManager = nullptr;
139 }
140 
QSessionManager(QGuiApplication * app,QString & id,QString & key)141 QSessionManager::QSessionManager(QGuiApplication *app, QString &id, QString &key)
142     : QObject(*(new QSessionManagerPrivate(id, key)), app)
143 {
144 }
145 
~QSessionManager()146 QSessionManager::~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 */
sessionId() const158 QString 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 */
sessionKey() const176 QString 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 */
allowsInteraction()212 bool 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 */
allowsErrorInteraction()229 bool 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 */
release()241 void 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 */
cancel()253 void 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 */
setRestartHint(QSessionManager::RestartHint hint)273 void 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 */
restartHint() const287 QSessionManager::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 */
setRestartCommand(const QStringList & command)314 void 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 */
restartCommand() const329 QStringList 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 */
setDiscardCommand(const QStringList & command)340 void 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 */
discardCommand() const355 QStringList 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 */
setManagerProperty(const QString & name,const QString & value)369 void 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 */
setManagerProperty(const QString & name,const QStringList & value)382 void 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 */
isPhase2() const395 bool 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 */
requestPhase2()418 void QSessionManager::requestPhase2()
419 {
420     Q_D(QSessionManager);
421     d->platformSessionManager->requestPhase2();
422 }
423 
424 QT_END_NAMESPACE
425 
426 #endif // QT_NO_SESSIONMANAGER
427