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