Skip to content

Commit

Permalink
Add option to disable "session management by closing windows".
Browse files Browse the repository at this point in the history
That feature is a poor man's session management for applications
that do not implement any specific session management features.
It badly interferes with proper session management support, so
applications must be able to disable it.

This enables fixing applications with
QGuiApplication::quitOnLastWindowClosed() true - the default -
dying too early, before they are enumerated for the list of
applications to restart on session restore, thus preventing them
from being restored. See
https://bugs.kde.org/show_bug.cgi?id=354724

[ChangeLog][QtGui] Qt asking to close windows on session exit as
a fallback session management mechanism has been made optional.
Disabling it fixes session management for applications that
implement full session management. See
QGuiApplication::isFallbackSessionManagementEnabled().

Task-number: QTBUG-49667
Change-Id: Ib22e58c9c64351dea8b7e2a74db91d26dd7ab7aa
Reviewed-by: Oswald Buddenhagen <[email protected]>
Reviewed-by: David Faure <[email protected]>
  • Loading branch information
ahartmetz authored and Jani Heikkinen committed Feb 15, 2016
1 parent 8c2b426 commit e7bf0ed
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 12 deletions.
16 changes: 16 additions & 0 deletions examples/widgets/mainwindows/application/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ MainWindow::MainWindow()
connect(textEdit->document(), &QTextDocument::contentsChanged,
this, &MainWindow::documentWasModified);

QGuiApplication::setFallbackSessionManagementEnabled(false);
connect(qApp, &QGuiApplication::commitDataRequest,
this, &MainWindow::commitData);

setCurrentFile(QString());
setUnifiedTitleAndToolBarOnMac(true);
}
Expand Down Expand Up @@ -383,3 +387,15 @@ QString MainWindow::strippedName(const QString &fullFileName)
return QFileInfo(fullFileName).fileName();
}
//! [49]

void MainWindow::commitData(QSessionManager &manager)
{
if (manager.allowsInteraction()) {
if (!maybeSave())
manager.cancel();
} else {
// Non-interactive: save without asking
if (textEdit->document()->isModified())
save();
}
}
2 changes: 2 additions & 0 deletions examples/widgets/mainwindows/application/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ QT_BEGIN_NAMESPACE
class QAction;
class QMenu;
class QPlainTextEdit;
class QSessionManager;
QT_END_NAMESPACE

//! [0]
Expand All @@ -69,6 +70,7 @@ private slots:
bool saveAs();
void about();
void documentWasModified();
void commitData(QSessionManager &);

private:
void createActions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ int main(int argc, char *argv[])
MyMainWidget::MyMainWidget(QWidget *parent)
:QWidget(parent)
{
QGuiApplication::setFallbackSessionManagementEnabled(false);
connect(qApp, SIGNAL(commitDataRequest(QSessionManager)), SLOT(commitData(QSessionManager)));
}

Expand Down
60 changes: 58 additions & 2 deletions src/gui/kernel/qguiapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ QPlatformTheme *QGuiApplicationPrivate::platform_theme = 0;

QList<QObject *> QGuiApplicationPrivate::generic_plugin_list;

bool QGuiApplicationPrivate::is_fallback_session_management_enabled = true;

enum ApplicationResourceFlags
{
ApplicationPaletteExplicitlySet = 0x1,
Expand Down Expand Up @@ -3082,6 +3084,55 @@ void QGuiApplicationPrivate::setApplicationState(Qt::ApplicationState state, boo
emit qApp->applicationStateChanged(applicationState);
}

// ### Qt6: consider removing the feature or making it less intrusive
/*!
\since 5.6
Returns whether QGuiApplication will use fallback session management.
The default is \c true.
If this is \c true and the session manager allows user interaction,
QGuiApplication will try to close toplevel windows after
commitDataRequest() has been emitted. If a window cannot be closed, session
shutdown will be canceled and the application will keep running.
Fallback session management only benefits applications that have an
"are you sure you want to close this window?" feature or other logic that
prevents closing a toplevel window depending on certain conditions, and
that do nothing to explicitly implement session management. In applications
that \e do implement session management using the proper session management
API, fallback session management interferes and may break session
management logic.
\warning If all windows \e are closed due to fallback session management
and quitOnLastWindowClosed() is \c true, the application will quit before
it is explicitly instructed to quit through the platform's session
management protocol. That violation of protocol may prevent the platform
session manager from saving application state.
\sa setFallbackSessionManagementEnabled(),
QSessionManager::allowsInteraction(), saveStateRequest(),
commitDataRequest(), {Session Management}
*/
bool QGuiApplication::isFallbackSessionManagementEnabled()
{
return QGuiApplicationPrivate::is_fallback_session_management_enabled;
}

/*!
\since 5.6
Sets whether QGuiApplication will use fallback session management to
\a enabled.
\sa isFallbackSessionManagementEnabled()
*/
void QGuiApplication::setFallbackSessionManagementEnabled(bool enabled)
{
QGuiApplicationPrivate::is_fallback_session_management_enabled = enabled;
}

/*!
\since 4.2
\fn void QGuiApplication::commitDataRequest(QSessionManager &manager)
Expand All @@ -3106,7 +3157,8 @@ void QGuiApplicationPrivate::setApplicationState(Qt::ApplicationState state, boo
\note You should use Qt::DirectConnection when connecting to this signal.
\sa isSessionRestored(), sessionId(), saveStateRequest(), {Session Management}
\sa setFallbackSessionManagementEnabled(), isSessionRestored(),
sessionId(), saveStateRequest(), {Session Management}
*/

/*!
Expand Down Expand Up @@ -3236,9 +3288,13 @@ void QGuiApplicationPrivate::commitData()
{
Q_Q(QGuiApplication);
is_saving_session = true;

emit q->commitDataRequest(*session_manager);
if (session_manager->allowsInteraction() && !tryCloseAllWindows())
if (is_fallback_session_management_enabled && session_manager->allowsInteraction()
&& !tryCloseAllWindows()) {
session_manager->cancel();
}

is_saving_session = false;
}

Expand Down
3 changes: 3 additions & 0 deletions src/gui/kernel/qguiapplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ class Q_GUI_EXPORT QGuiApplication : public QCoreApplication
QString sessionId() const;
QString sessionKey() const;
bool isSavingSession() const;

static bool isFallbackSessionManagementEnabled();
static void setFallbackSessionManagementEnabled(bool);
#endif

static void sync();
Expand Down
1 change: 1 addition & 0 deletions src/gui/kernel/qguiapplication_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ class Q_GUI_EXPORT QGuiApplicationPrivate : public QCoreApplicationPrivate
#endif

#ifndef QT_NO_SESSIONMANAGER
static bool is_fallback_session_management_enabled;
QSessionManager *session_manager;
bool is_session_restored;
bool is_saving_session;
Expand Down
19 changes: 9 additions & 10 deletions src/gui/kernel/qsessionmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,21 @@ QT_BEGIN_NAMESPACE
settings.
QSessionManager provides an interface between the application and the
session manager so that the program can work well with the session manager.
In Qt, session management requests for action are handled by the two
signals QGuiApplication::commitDataRequest() and
QGuiApplication::saveStateRequest(). Both provide a reference to a session
manager object as argument, to allow the application to communicate with
the session manager. The session manager can only be accessed through these
functions.
platform's session manager. In Qt, session management requests for action
are handled by the two signals QGuiApplication::commitDataRequest() and
QGuiApplication::saveStateRequest(). Both provide a reference to a
QSessionManager object as argument. The session manager can only be
accessed in slots invoked by these signals.
\warning If you use QSessionManager, you should disable fallback session
management: QGuiApplication::setFallbackSessionManagementEnabled().
No user interaction is possible \e unless the application gets explicit
permission from the session manager. You ask for permission by calling
allowsInteraction() or, if it is really urgent, allowsErrorInteraction().
Qt does not enforce this, but the session manager may.
You can try to abort the shutdown process by calling cancel(). The default
commitData() function does this if some top-level window rejected its
closeEvent().
You can try to abort the shutdown process by calling cancel().
For sophisticated session managers provided on Unix/X11, QSessionManager
offers further possibilities to fine-tune an application's session
Expand Down

0 comments on commit e7bf0ed

Please sign in to comment.