kxmlgui/fix-session-saving.patch

104 lines
3.6 KiB
Diff

diff --git a/src/kmainwindow.cpp b/src/kmainwindow.cpp
index cae655d..7455132 100644
--- a/src/kmainwindow.cpp
+++ b/src/kmainwindow.cpp
@@ -121,14 +121,18 @@ KMWSessionManager::KMWSessionManager()
{
connect(qApp, SIGNAL(saveStateRequest(QSessionManager&)),
this, SLOT(saveState(QSessionManager&)));
+ connect(qApp, SIGNAL(commitDataRequest(QSessionManager&)),
+ this, SLOT(commitData(QSessionManager&)));
}
KMWSessionManager::~KMWSessionManager()
{
}
-bool KMWSessionManager::saveState(QSessionManager &sm)
+void KMWSessionManager::saveState(QSessionManager &sm)
{
+ sm.setAutoCloseWindowsEnabled(false);
+
KConfigGui::setSessionConfig(sm.sessionId(), sm.sessionKey());
KConfig *config = KConfigGui::sessionConfig();
@@ -158,8 +162,58 @@ bool KMWSessionManager::saveState(QSessionManager &sm)
discard << localFilePath;
sm.setDiscardCommand(discard);
}
+}
- return true;
+void KMWSessionManager::commitData(QSessionManager &sm)
+{
+ // Prevents QGuiApplication::commitData() from closing our windows with tryCloseAllWindows()
+ sm.setAutoCloseWindowsEnabled(false);
+ if (!sm.allowsInteraction()) {
+ return;
+ }
+
+ /*
+ Purpose of this exercise: invoke queryClose() without actually closing the
+ windows, because
+ - queryClose() may contain session management code, so it must be invoked
+ - closing windows may quit the application
+ (cf. QGuiApplication::quitOnLastWindowClosed())
+ - quitting the application and thus closing the session manager connection
+ violates the X11 XSMP protocol.
+ The exact requirement of XSMP that would be broken is,
+ in the description of the client's state machine:
+
+ save-yourself-done: (changing state is forbidden)
+
+ Closing the session manager connection causes a state change.
+ Worst of all, that is an actual problem with ksmserver - it will not save
+ applications that quit on their own in state save-yourself-done.
+ */
+ foreach (KMainWindow *window, KMainWindow::memberList()) {
+ if (window->testAttribute(Qt::WA_WState_Hidden)) {
+ continue;
+ }
+ QCloseEvent e;
+ QApplication::sendEvent(window, &e);
+ if (!e.isAccepted()) {
+ sm.cancel();
+ break;
+ }
+ /* Don't even think_about deleting widgets with
+ Qt::WDestructiveClose flag set at this point. We
+ are faking a close event, but we are *not*_
+ closing the window. The purpose of the faked
+ close event is to prepare the application so it
+ can safely be quit without the user losing data
+ (possibly showing a message box "do you want to
+ save this or that?"). It is possible that the
+ session manager quits the application later
+ (emitting QApplication::aboutToQuit() when this
+ happens), but it is also possible that the user
+ cancels the shutdown, so the application will
+ continue to run.
+ */
+ }
}
Q_GLOBAL_STATIC(KMWSessionManager, ksm)
@@ -893,4 +947,3 @@ QString KMainWindow::dbusName() const
}
#include "moc_kmainwindow.cpp"
-
diff --git a/src/kmainwindow_p.h b/src/kmainwindow_p.h
index 8204ce1..910680d 100644
--- a/src/kmainwindow_p.h
+++ b/src/kmainwindow_p.h
@@ -81,7 +81,8 @@ public:
~KMWSessionManager();
private Q_SLOTS:
- bool saveState(QSessionManager &);
+ void saveState(QSessionManager &);
+ void commitData(QSessionManager &);
};
#endif