diff --git a/ksmserver/CMakeLists.txt b/ksmserver/CMakeLists.txt --- a/ksmserver/CMakeLists.txt +++ b/ksmserver/CMakeLists.txt @@ -44,7 +44,7 @@ qt5_add_dbus_interface( ksmserver_KDEINIT_SRCS ${klauncher_xml} klauncher_interface ) qt5_add_dbus_interface( ksmserver_KDEINIT_SRCS ${KSCREENLOCKER_DBUS_INTERFACES_DIR}/org.kde.screensaver.xml kscreenlocker_interface ) - +qt5_add_dbus_interface( ksmserver_KDEINIT_SRCS org.kde.LogoutPrompt.xml logoutprompt_interface) qt5_add_dbus_adaptor( ksmserver_KDEINIT_SRCS org.kde.KSMServerInterface.xml server.h KSMServer ) diff --git a/ksmserver/org.kde.LogoutPrompt.xml b/ksmserver/org.kde.LogoutPrompt.xml new file mode 100644 --- /dev/null +++ b/ksmserver/org.kde.LogoutPrompt.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/ksmserver/server.h b/ksmserver/server.h --- a/ksmserver/server.h +++ b/ksmserver/server.h @@ -239,7 +239,6 @@ ClosingSubSession, KillingSubSession, RestoringSubSession }; State state; - bool dialogActive; bool saveSession; int wmPhase1WaitingCount; int saveType; @@ -289,7 +288,6 @@ QList clientsToSave; int sockets[2]; - friend bool readFromPipe(int pipe); }; #endif diff --git a/ksmserver/server.cpp b/ksmserver/server.cpp --- a/ksmserver/server.cpp +++ b/ksmserver/server.cpp @@ -624,7 +624,6 @@ shutdownType = KWorkSpace::ShutdownTypeNone; state = Idle; - dialogActive = false; saveSession = false; wmPhase1WaitingCount = 0; KConfigGroup config(KSharedConfig::openConfig(), "General"); diff --git a/ksmserver/shutdown.cpp b/ksmserver/shutdown.cpp --- a/ksmserver/shutdown.cpp +++ b/ksmserver/shutdown.cpp @@ -77,6 +77,7 @@ #include "client.h" #include +#include "logoutprompt_interface.h" #include #include @@ -108,34 +109,12 @@ return state >= Shutdown; } -bool readFromPipe(int pipe) -{ - QFile readPipe; - if (!readPipe.open(pipe, QIODevice::ReadOnly)) { - return false; - } - QByteArray result = readPipe.readLine(); - if (result.isEmpty()) { - return false; - } - bool ok = false; - const int number = result.toInt(&ok); - if (!ok) { - return false; - } - KSMServer::self()->shutdownType = KWorkSpace::ShutdownType(number); - - return true; -} - void KSMServer::shutdown( KWorkSpace::ShutdownConfirm confirm, KWorkSpace::ShutdownType sdtype, KWorkSpace::ShutdownMode sdmode ) { qCDebug(KSMSERVER) << "Shutdown called with confirm " << confirm << " type " << sdtype << " and mode " << sdmode; pendingShutdown.stop(); - if( dialogActive ) - return; if( state >= Shutdown ) // already performing shutdown return; if( state != Idle ) // performing startup @@ -160,129 +139,27 @@ (confirm == KWorkSpace::ShutdownConfirmYes) ? false : (confirm == KWorkSpace::ShutdownConfirmNo) ? true : !cg.readEntry( "confirmLogout", true ); - bool choose = false; - bool maysd = false; - if (cg.readEntry( "offerShutdown", true ) && KDisplayManager().canShutdown()) - maysd = true; - if (!maysd) { - if (sdtype != KWorkSpace::ShutdownTypeNone && - sdtype != KWorkSpace::ShutdownTypeDefault && - logoutConfirmed) - return; /* unsupported fast shutdown */ - sdtype = KWorkSpace::ShutdownTypeNone; - } else if (sdtype == KWorkSpace::ShutdownTypeDefault) { - sdtype = (KWorkSpace::ShutdownType) - cg.readEntry( "shutdownType", (int)KWorkSpace::ShutdownTypeNone ); - choose = true; - } - if (sdmode == KWorkSpace::ShutdownModeDefault) - sdmode = KWorkSpace::ShutdownModeInteractive; - - qCDebug(KSMSERVER) << "After modifications confirm is " << confirm - << " type is " << sdtype << " and mode " << sdmode; - QString bopt; - if ( !logoutConfirmed ) { - int pipeFds[2]; - if (pipe(pipeFds) != 0) { - return; - } - QProcess *p = new QProcess(this); - p->setProgram(QStringLiteral(LOGOUT_GREETER_BIN)); - QStringList arguments; - if (maysd) { - arguments << QStringLiteral("--shutdown-allowed"); - } - if (choose) { - arguments << QStringLiteral("--choose"); - } - if (sdtype != KWorkSpace::ShutdownTypeDefault) { - arguments << QStringLiteral("--mode"); - switch (sdtype) { - case KWorkSpace::ShutdownTypeHalt: - arguments << QStringLiteral("shutdown"); - break; - case KWorkSpace::ShutdownTypeReboot: - arguments << QStringLiteral("reboot"); - break; - case KWorkSpace::ShutdownTypeNone: - default: - // logout - arguments << QStringLiteral("logout"); - break; - } - } - arguments << QStringLiteral("--mode-fd"); - arguments << QString::number(pipeFds[1]); - p->setArguments(arguments); - - const int resultPipe = pipeFds[0]; - connect(p, static_cast(&QProcess::error), this, - [this, resultPipe, sdmode, sdtype] { - close(resultPipe); - dialogActive = false; - auto fallbackPrompt = new QMessageBox; - fallbackPrompt->setAttribute(Qt::WA_DeleteOnClose, true); - fallbackPrompt->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); - switch (sdtype) { - case KWorkSpace::ShutdownTypeHalt: - //i18nd is used as this patch was backported to an LTS with stable translations - fallbackPrompt->setText(i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Shut Down")); - break; - case KWorkSpace::ShutdownTypeReboot: - fallbackPrompt->setText(i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Reboot")); - break; - case KWorkSpace::ShutdownTypeNone: - Q_FALLTHROUGH(); - default: - fallbackPrompt->setText(i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Logout")); - break; - } - connect(fallbackPrompt, &QMessageBox::buttonClicked, this, [=](QAbstractButton *button) { - if (button != fallbackPrompt->button(QMessageBox::Ok)) { - return; - } - shutdownType = sdtype; - shutdownMode = sdmode; - bootOption = QString(); - performLogout(); - }); - fallbackPrompt->show(); - } - ); - - connect(p, static_cast(&QProcess::finished), this, - [this, resultPipe, sdmode, p] (int exitCode) { - p->deleteLater(); - dialogActive = false; - if (exitCode != 0) { - close(resultPipe); - return; - } - QFutureWatcher *watcher = new QFutureWatcher(); - QObject::connect(watcher, &QFutureWatcher::finished, this, - [this, sdmode, watcher] { - const bool result = watcher->result(); - if (!result) { - // it failed to read, don't logout - return; - } - shutdownMode = sdmode; - bootOption = QString(); - performLogout(); - }, Qt::QueuedConnection); - QObject::connect(watcher, &QFutureWatcher::finished, watcher, &QFutureWatcher::deleteLater, Qt::QueuedConnection); - watcher->setFuture(QtConcurrent::run(readFromPipe, resultPipe)); - } - ); - dialogActive = true; - p->start(); - close(pipeFds[1]); + if (!logoutConfirmed) { + OrgKdeLogoutPromptInterface logoutPrompt(QStringLiteral("org.kde.LogoutPrompt"), + QStringLiteral("/LogoutPrompt"), + QDBusConnection::sessionBus()); + switch (sdtype) { + case KWorkSpace::ShutdownTypeHalt: + logoutPrompt.promptShutDown(); + break; + case KWorkSpace::ShutdownTypeReboot: + logoutPrompt.promptReboot(); + break; + case KWorkSpace::ShutdownTypeNone: + Q_FALLTHROUGH(); + default: + logoutPrompt.promptLogout(); + break; + } } else { shutdownType = sdtype; shutdownMode = sdmode; - bootOption = bopt; - performLogout(); } } @@ -349,7 +226,6 @@ qCDebug(KSMSERVER) << "clients should be empty, " << clients.isEmpty(); if ( clients.isEmpty() ) completeShutdownOrCheckpoint(); - dialogActive = false; } void KSMServer::pendingShutdownTimeout() @@ -359,7 +235,7 @@ void KSMServer::saveCurrentSession() { - if ( state != Idle || dialogActive ) + if ( state != Idle ) return; if ( currentSession().isEmpty() || currentSession() == QString::fromLocal8Bit( SESSION_PREVIOUS_LOGOUT ) ) @@ -392,7 +268,7 @@ void KSMServer::saveCurrentSessionAs( const QString &session ) { - if ( state != Idle || dialogActive ) + if ( state != Idle ) return; sessionGroup = QStringLiteral( "Session: " ) + session; saveCurrentSession(); diff --git a/logout-greeter/CMakeLists.txt b/logout-greeter/CMakeLists.txt --- a/logout-greeter/CMakeLists.txt +++ b/logout-greeter/CMakeLists.txt @@ -4,6 +4,10 @@ CATEGORY_NAME kde.logout_greeter DEFAULT_SEVERITY Info) + +qt5_add_dbus_adaptor( LOGOUT_GREETER_SRCS ../ksmserver/org.kde.LogoutPrompt.xml greeter.h Greeter) +qt5_add_dbus_interface( LOGOUT_GREETER_SRCS ../ksmserver/org.kde.KSMServerInterface.xml ksmserveriface) + add_executable(ksmserver-logout-greeter ${LOGOUT_GREETER_SRCS}) target_link_libraries(ksmserver-logout-greeter PW::KWorkspace @@ -20,6 +24,7 @@ ${X11_LIBRARIES} ) install(TARGETS ksmserver-logout-greeter DESTINATION ${KDE_INSTALL_LIBEXECDIR}) +kdbusaddons_generate_dbus_service_file(ksmserver-logout-greeter org.kde.LogoutPrompt ${KDE_INSTALL_FULL_LIBEXECDIR}) if(BUILD_TESTING) add_subdirectory(tests) diff --git a/logout-greeter/greeter.h b/logout-greeter/greeter.h --- a/logout-greeter/greeter.h +++ b/logout-greeter/greeter.h @@ -43,22 +43,27 @@ { Q_OBJECT public: - Greeter(int fd, bool shutdownAllowed, bool choose, KWorkSpace::ShutdownType type); + Greeter(bool shutdownAllowed); ~Greeter() override; void init(); bool eventFilter(QObject *watched, QEvent *event) override; +public Q_SLOTS: + void promptLogout(); + void promptShutDown(); + void promptReboot(); + private: void adoptScreen(QScreen *screen); void rejected(); void setupWaylandIntegration(); - int m_fd; bool m_shutdownAllowed; - bool m_choose; - KWorkSpace::ShutdownType m_shutdownType; + bool m_running = false; + + KWorkSpace::ShutdownType m_shutdownType = KWorkSpace::ShutdownTypeHalt; QVector m_dialogs; KWayland::Client::PlasmaShell *m_waylandPlasmaShell; }; diff --git a/logout-greeter/greeter.cpp b/logout-greeter/greeter.cpp --- a/logout-greeter/greeter.cpp +++ b/logout-greeter/greeter.cpp @@ -31,23 +31,24 @@ #include "shutdowndlg.h" +#include "logoutpromptadaptor.h" +#include "ksmserveriface.h" + #include #include #include #include #include -#include - -Greeter::Greeter(int fd, bool shutdownAllowed, bool choose, KWorkSpace::ShutdownType type) +Greeter::Greeter(bool shutdownAllowed) : QObject() - , m_fd(fd) , m_shutdownAllowed(shutdownAllowed) - , m_choose(choose) - , m_shutdownType(type) , m_waylandPlasmaShell(nullptr) { + new LogoutPromptAdaptor(this); + QDBusConnection::sessionBus().registerObject(QStringLiteral("/LogoutPrompt"), this); + QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.LogoutPrompt")); } Greeter::~Greeter() @@ -83,42 +84,33 @@ adoptScreen(screen); } connect(qApp, &QGuiApplication::screenAdded, this, &Greeter::adoptScreen); + m_running = true; } void Greeter::adoptScreen(QScreen* screen) { // TODO: last argument is the theme, maybe add command line option for it? - KSMShutdownDlg *w = new KSMShutdownDlg(nullptr, m_shutdownAllowed, m_choose, m_shutdownType, m_waylandPlasmaShell); + KSMShutdownDlg *w = new KSMShutdownDlg(nullptr, m_shutdownAllowed, m_shutdownType, m_waylandPlasmaShell); w->installEventFilter(this); m_dialogs << w; QObject::connect(screen, &QObject::destroyed, w, [w, this] { m_dialogs.removeOne(w); w->deleteLater(); }); connect(w, &KSMShutdownDlg::rejected, this, &Greeter::rejected); - connect(w, &KSMShutdownDlg::accepted, this, - [w, this] { - if (m_fd != -1) { - QFile f; - if (f.open(m_fd, QFile::WriteOnly, QFile::AutoCloseHandle)) { - f.write(QByteArray::number(int(w->shutdownType()))); - f.close(); - } - } - QApplication::quit(); - } - ); + connect(w, &KSMShutdownDlg::accepted, this, [w]() { + OrgKdeKSMServerInterfaceInterface ksmserver(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QDBusConnection::sessionBus()); + ksmserver.logout(KWorkSpace::ShutdownConfirmNo, w->shutdownType(), KWorkSpace::ShutdownModeDefault); + QApplication::exit(1); + }); w->setScreen(screen); w->setGeometry(screen->geometry()); w->init(); } void Greeter::rejected() { - if (m_fd != -1) { - close(m_fd); - } QApplication::exit(1); } @@ -139,3 +131,32 @@ } return false; } + +void Greeter::promptLogout() +{ + if (m_running) { + return; + } + m_shutdownType = KWorkSpace::ShutdownTypeLogout; + init(); +} + +void Greeter::promptShutDown() +{ + if (m_running) { + return; + } + m_shutdownType = KWorkSpace::ShutdownTypeHalt; + init(); +} + +void Greeter::promptReboot() +{ + if (m_running) { + return; + } + m_shutdownType = KWorkSpace::ShutdownTypeReboot; + init(); +} + + diff --git a/logout-greeter/main.cpp b/logout-greeter/main.cpp --- a/logout-greeter/main.cpp +++ b/logout-greeter/main.cpp @@ -28,7 +28,7 @@ #include -#include +#include "ksmserveriface.h" #include "greeter.h" @@ -38,64 +38,35 @@ // Before Qt 5.12, the xdg-shell v6 integration does not support fullscreen. qputenv("QT_WAYLAND_SHELL_INTEGRATION", "wl-shell"); } + qunsetenv("SESSION_MANAGER"); KWorkSpace::detectPlatform(argc, argv); QQuickWindow::setDefaultAlphaBuffer(true); QApplication app(argc, argv); KQuickAddons::QtQuickSettings::init(); - QCommandLineParser parser; - parser.addHelpOption(); - - // TODO: should these things be translated? It's internal after all... - QCommandLineOption shutdownAllowedOption(QStringLiteral("shutdown-allowed"), - QStringLiteral("Whether the user is allowed to shut down the system.")); - parser.addOption(shutdownAllowedOption); - - QCommandLineOption chooseOption(QStringLiteral("choose"), - QStringLiteral("Whether the user is offered the choices between logout, shutdown, etc.")); - parser.addOption(chooseOption); - - QCommandLineOption modeOption(QStringLiteral("mode"), - QStringLiteral("The initial exit mode to offer to the user."), - QStringLiteral("logout|shutdown|reboot"), - QStringLiteral("logout")); - parser.addOption(modeOption); - - QCommandLineOption fdOption(QStringLiteral("mode-fd"), - QStringLiteral("An optional file descriptor the selected mode is written to on accepted"), - QStringLiteral("fd"), QString::number(-1)); - parser.addOption(fdOption); - - parser.process(app); - - KWorkSpace::ShutdownType type = KWorkSpace::ShutdownTypeDefault; - if (parser.isSet(modeOption)) { - const QString modeValue = parser.value(modeOption); - if (QString::compare(QLatin1String("logout"), modeValue, Qt::CaseInsensitive) == 0) { - type = KWorkSpace::ShutdownTypeNone; - } else if (QString::compare(QLatin1String("shutdown"), modeValue, Qt::CaseInsensitive) == 0) { - type = KWorkSpace::ShutdownTypeHalt; - } else if (QString::compare(QLatin1String("reboot"), modeValue, Qt::CaseInsensitive) == 0) { - type = KWorkSpace::ShutdownTypeReboot; - } else { - return 1; - } + OrgKdeKSMServerInterfaceInterface ksmserver(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QDBusConnection::sessionBus()); + QDBusPendingReply isShuttingDownPending = ksmserver.isShuttingDown(); + QDBusPendingReply canShutdownPending = ksmserver.canShutdown(); + + isShuttingDownPending.waitForFinished(); + canShutdownPending.waitForFinished(); + + //if ksmserver is shutting us down already, we don't want another prompt + if (isShuttingDownPending.value()) { + return 0; } - int fd = -1; - if (parser.isSet(fdOption)) { - bool ok = false; - const int passedFd = parser.value(fdOption).toInt(&ok); - if (ok) { - fd = dup(passedFd); - } + bool shutdownAllowed = canShutdownPending.value(); + + Greeter greeter(shutdownAllowed); + + if (argc > 1) { + //special case, invoked from ksmserver from a former release which had a tonne of args + //shouldn't happen often + greeter.promptLogout(); } - Greeter greeter(fd, parser.isSet(shutdownAllowedOption), parser.isSet(chooseOption), type); - greeter.init(); return app.exec(); } - -#include "main.moc" diff --git a/logout-greeter/shutdowndlg.h b/logout-greeter/shutdowndlg.h --- a/logout-greeter/shutdowndlg.h +++ b/logout-greeter/shutdowndlg.h @@ -43,7 +43,7 @@ Q_OBJECT public: - KSMShutdownDlg( QWindow* parent, bool maysd, bool choose, KWorkSpace::ShutdownType sdtype, KWayland::Client::PlasmaShell *plasmaShell = nullptr ); + KSMShutdownDlg( QWindow* parent, bool maysd, KWorkSpace::ShutdownType sdtype, KWayland::Client::PlasmaShell *plasmaShell = nullptr ); void init(); bool result() const; diff --git a/logout-greeter/shutdowndlg.cpp b/logout-greeter/shutdowndlg.cpp --- a/logout-greeter/shutdowndlg.cpp +++ b/logout-greeter/shutdowndlg.cpp @@ -68,8 +68,8 @@ Q_DECLARE_METATYPE(Solid::PowerManagement::SleepState) -KSMShutdownDlg::KSMShutdownDlg( QWindow* parent, - bool maysd, bool choose, KWorkSpace::ShutdownType sdtype, +KSMShutdownDlg::KSMShutdownDlg(QWindow* parent, + bool maysd, KWorkSpace::ShutdownType sdtype, KWayland::Client::PlasmaShell *plasmaShell) : QuickViewSharedEngine(parent), m_result(false), @@ -100,7 +100,6 @@ //windowContainer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); QQmlContext *context = rootContext(); context->setContextProperty(QStringLiteral("maysd"), maysd); - context->setContextProperty(QStringLiteral("choose"), choose); context->setContextProperty(QStringLiteral("sdtype"), sdtype); QQmlPropertyMap *mapShutdownType = new QQmlPropertyMap(this); @@ -122,6 +121,10 @@ // TODO KF6 remove, used to read "BootManager" from kdmrc context->setContextProperty(QStringLiteral("bootManager"), QStringLiteral("None")); + //TODO KF6 remove. Unused + context->setContextProperty(QStringLiteral("choose"), false); + + // TODO KF6 remove, used to call KDisplayManager::bootOptions QStringList rebootOptions; int def = 0;