diff --git a/main.h b/main.h --- a/main.h +++ b/main.h @@ -238,7 +238,6 @@ } protected: - QString m_originalSessionKey; static int crashes; private Q_SLOTS: diff --git a/main.cpp b/main.cpp --- a/main.cpp +++ b/main.cpp @@ -276,7 +276,7 @@ // critical startup section where x errors cause kwin to abort. // create workspace. - (void) new Workspace(m_originalSessionKey); + (void) new Workspace(); emit workspaceCreated(); } diff --git a/main_x11.cpp b/main_x11.cpp --- a/main_x11.cpp +++ b/main_x11.cpp @@ -216,11 +216,6 @@ Application::setX11ScreenNumber(QX11Info::appScreen()); } - // QSessionManager for some reason triggers a very early commitDataRequest - // and updates the key - before we create the workspace and load the session - // data -> store and pass to the workspace constructor - m_originalSessionKey = sessionKey(); - owner.reset(new KWinSelectionOwner(Application::x11ScreenNumber())); connect(owner.data(), &KSelectionOwner::failedToClaimOwnership, []{ fputs(i18n("kwin: unable to claim manager selection, another wm running? (try using --replace)\n").toLocal8Bit().constData(), stderr); @@ -420,6 +415,8 @@ qunsetenv("QT_DEVICE_PIXEL_RATIO"); qunsetenv("QT_SCALE_FACTOR"); QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); + // KSMServer talks to us directly on DBus. + QCoreApplication::setAttribute(Qt::AA_DisableSessionManager); KWin::ApplicationX11 a(argc, argv); a.setupTranslator(); diff --git a/org.kde.KWin.Session.xml b/org.kde.KWin.Session.xml --- a/org.kde.KWin.Session.xml +++ b/org.kde.KWin.Session.xml @@ -10,6 +10,15 @@ --> + + + + + + + + + diff --git a/sm.h b/sm.h --- a/sm.h +++ b/sm.h @@ -45,8 +45,15 @@ Q_SIGNALS: void stateChanged(); + void loadSessionRequested(const QString &name); + void prepareSessionSaveRequested(const QString &name); + void finishSessionSaveRequested(const QString &name); + public Q_SLOTS: // DBus API void setState(uint state); + void loadSession(const QString &name); + void aboutToSaveSession(const QString &name); + void finishSaveSession(const QString &name); private: void setState(SessionState state); diff --git a/sm.cpp b/sm.cpp --- a/sm.cpp +++ b/sm.cpp @@ -81,46 +81,16 @@ return static_cast< NET::WindowType >(-2); // undefined } -void Workspace::saveState(QSessionManager &sm) -{ - bool sessionManagerIsKSMServer = QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.ksmserver").value(); - - // If the session manager is ksmserver, save stacking - // order, active window, active desktop etc. in phase 1, - // as ksmserver assures no interaction will be done - // before the WM finishes phase 1. Saving in phase 2 is - // too late, as possible user interaction may change some things. - // Phase2 is still needed though (ICCCM 5.2) - KConfig *config = sessionConfig(sm.sessionId(), sm.sessionKey()); - if (!sm.isPhase2()) { - KConfigGroup cg(config, "Session"); - cg.writeEntry("AllowsInteraction", sm.allowsInteraction()); - if (sessionManagerIsKSMServer) // save stacking order etc. before "save file?" etc. dialogs change it - storeSession(config, SMSavePhase0); - config->markAsClean(); // don't write Phase #1 data to disk - sm.release(); // Qt doesn't automatically release in this case (bug?) - sm.requestPhase2(); - return; - } - storeSession(config, sessionManagerIsKSMServer ? SMSavePhase2 : SMSavePhase2Full); - config->sync(); - - // inform the smserver on how to clean-up after us - const QString localFilePath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + config->name(); - if (QFile::exists(localFilePath)) { // expectable for the sync - sm.setDiscardCommand(QStringList() << QStringLiteral("rm") << localFilePath); - } -} - -// Workspace - /** * Stores the current session in the config file * * @see loadSessionInfo */ -void Workspace::storeSession(KConfig* config, SMSavePhase phase) +void Workspace::storeSession(const QString &sessionName, SMSavePhase phase) { + qCDebug(KWIN_CORE) << "storing session" << sessionName << "in phase" << phase; + KConfig *config = sessionConfig(sessionName, QString()); + KConfigGroup cg(config, "Session"); int count = 0; int active_client = -1; @@ -160,6 +130,7 @@ cg.writeEntry("active", session_active_client); cg.writeEntry("desktop", VirtualDesktopManager::self()->current()); } + config->sync(); // it previously did some "revert to defaults" stuff for phase1 I think } void Workspace::storeClient(KConfigGroup &cg, int num, X11Client *c) @@ -235,12 +206,10 @@ * * @see storeSession */ -void Workspace::loadSessionInfo(const QString &key) +void Workspace::loadSessionInfo(const QString &sessionName) { - // NOTICE: qApp->sessionKey() is outdated when this gets invoked - // the key parameter is cached from the application constructor. session.clear(); - KConfigGroup cg(sessionConfig(qApp->sessionId(), key), "Session"); + KConfigGroup cg(sessionConfig(sessionName, QString()), "Session"); addSessionInfo(cg); } @@ -385,6 +354,7 @@ } } +// TODO should we rethink this now that we have dedicated start end end save methods? void SessionManager::setState(SessionState state) { if (state == m_sessionState) { @@ -405,5 +375,20 @@ emit stateChanged(); } +void SessionManager::loadSession(const QString &name) +{ + emit loadSessionRequested(name); +} + +void SessionManager::aboutToSaveSession(const QString &name) +{ + emit prepareSessionSaveRequested(name); +} + +void SessionManager::finishSaveSession(const QString &name) +{ + emit finishSessionSaveRequested(name); +} + } // namespace diff --git a/workspace.h b/workspace.h --- a/workspace.h +++ b/workspace.h @@ -69,7 +69,7 @@ { Q_OBJECT public: - explicit Workspace(const QString &sessionKey = QString()); + explicit Workspace(); ~Workspace() override; static Workspace* self() { @@ -309,7 +309,7 @@ void updateOnAllDesktopsOfTransients(AbstractClient*); void checkTransients(xcb_window_t w); - void storeSession(KConfig* config, SMSavePhase phase); + void storeSession(const QString &sessionName, SMSavePhase phase); void storeClient(KConfigGroup &cg, int num, X11Client *c); void storeSubSession(const QString &name, QSet sessionIds); void loadSubSessionInfo(const QString &name); @@ -494,9 +494,6 @@ void slotDesktopCountChanged(uint previousCount, uint newCount); void slotCurrentDesktopChanged(uint oldDesktop, uint newDesktop); - // session management - void saveState(QSessionManager &sm); - Q_SIGNALS: /** * Emitted after the Workspace has setup the complete initialization process. @@ -581,7 +578,7 @@ AbstractClient* active_popup_client; int m_initialDesktop; - void loadSessionInfo(const QString &key); + void loadSessionInfo(const QString &sessionName); void addSessionInfo(KConfigGroup &cg); QList session; diff --git a/workspace.cpp b/workspace.cpp --- a/workspace.cpp +++ b/workspace.cpp @@ -102,7 +102,7 @@ Workspace* Workspace::_self = nullptr; -Workspace::Workspace(const QString &sessionKey) +Workspace::Workspace() : QObject(nullptr) , m_compositor(nullptr) // Unsorted @@ -153,10 +153,6 @@ delayFocusTimer = nullptr; - if (!sessionKey.isEmpty()) - loadSessionInfo(sessionKey); - connect(qApp, &QGuiApplication::saveStateRequest, this, &Workspace::saveState); - RuleBook::create(this)->load(); kwinApp()->createScreens(); @@ -187,6 +183,15 @@ decorationBridge->init(); connect(this, &Workspace::configChanged, decorationBridge, &Decoration::DecorationBridge::reconfigure); + connect(m_sessionManager, &SessionManager::loadSessionRequested, this, &Workspace::loadSessionInfo); + + connect(m_sessionManager, &SessionManager::prepareSessionSaveRequested, this, [this](const QString &name) { + storeSession(name, SMSavePhase0); + }); + connect(m_sessionManager, &SessionManager::finishSessionSaveRequested, this, [this](const QString &name) { + storeSession(name, SMSavePhase2); + }); + new DBusInterface(this); Outline::create(this);