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 | |
122 | QSessionManagerPrivate::QSessionManagerPrivate(const QString &id, |
123 | const QString &key) |
124 | : QObjectPrivate() |
125 | { |
126 | if (qApp->testAttribute(attribute: 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 | |
135 | QSessionManagerPrivate::~QSessionManagerPrivate() |
136 | { |
137 | delete platformSessionManager; |
138 | platformSessionManager = nullptr; |
139 | } |
140 | |
141 | QSessionManager::QSessionManager(QGuiApplication *app, QString &id, QString &key) |
142 | : QObject(*(new QSessionManagerPrivate(id, key)), app) |
143 | { |
144 | } |
145 | |
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 | */ |
158 | 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 | */ |
176 | 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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
287 | 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 | */ |
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 | */ |
329 | 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 | */ |
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 | */ |
355 | 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 | */ |
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 | */ |
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 | */ |
395 | 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 | */ |
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 | |