diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ include(ECMQueryQmake) include(KDEPackageAppTemplates) include(KDEClangFormat) +include(ECMConfiguredInstall) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Plasma DocTools Runner Notifications NotifyConfig Su NewStuff Wallet @@ -149,6 +150,8 @@ # locate qdbus in the Qt path because not every distro makes a symlink at /usr/bin/qdbus query_qmake(QtBinariesDir QT_INSTALL_BINS) +option(PLASMA_SYSTEMD_BOOT "Use systemd units for startup of plasma (WIP)" FALSE) + add_subdirectory(doc) add_subdirectory(libkworkspace) add_subdirectory(libdbusmenuqt) diff --git a/config-workspace.h.cmake b/config-workspace.h.cmake --- a/config-workspace.h.cmake +++ b/config-workspace.h.cmake @@ -155,3 +155,5 @@ /** place where plasma-frameworks things are installed */ #define PLASMA_RELATIVE_DATA_INSTALL_DIR "@PLASMA_RELATIVE_DATA_INSTALL_DIR@" + +#cmakedefine PLASMA_SYSTEMD_BOOT 1 diff --git a/gmenu-dbusmenu-proxy/gmenudbusmenuproxy.desktop b/gmenu-dbusmenu-proxy/gmenudbusmenuproxy.desktop --- a/gmenu-dbusmenu-proxy/gmenudbusmenuproxy.desktop +++ b/gmenu-dbusmenu-proxy/gmenudbusmenuproxy.desktop @@ -36,3 +36,4 @@ X-KDE-StartupNotify=false OnlyShowIn=KDE; X-KDE-autostart-phase=1 +X-systemd-hidden=true diff --git a/gmenu-dbusmenu-proxy/plasma-gmenudbusproxy.service.in b/gmenu-dbusmenu-proxy/plasma-gmenudbusproxy.service.in new file mode 100644 --- /dev/null +++ b/gmenu-dbusmenu-proxy/plasma-gmenudbusproxy.service.in @@ -0,0 +1,13 @@ +[Unit] +Description=Proxies GTK DBus menus to a Plasma readable format + +[Service] +ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/gmenudbusmenuproxy +Restart=on-failure +KillMode=process +Type=simple +Slice=background.slice +TimeoutSec=5sec + +[Install] +WantedBy=plasma-workspace.target diff --git a/krunner/CMakeLists.txt b/krunner/CMakeLists.txt --- a/krunner/CMakeLists.txt +++ b/krunner/CMakeLists.txt @@ -41,4 +41,7 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KRunnerAppDBusInterfaceConfig.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) +ecm_install_configured_files(TEMPLATES plasma-krunner.service.in @ONLY DESTINATION + ${SYSTEMD_USER_UNIT_INSTALL_DIR}) + add_subdirectory(update) diff --git a/krunner/dbus/org.kde.krunner.service.in b/krunner/dbus/org.kde.krunner.service.in --- a/krunner/dbus/org.kde.krunner.service.in +++ b/krunner/dbus/org.kde.krunner.service.in @@ -1,3 +1,4 @@ [D-BUS Service] Name=org.kde.krunner Exec=@KDE_INSTALL_FULL_BINDIR@/krunner +SystemdService=krunner.service diff --git a/krunner/plasma-krunner.service.in b/krunner/plasma-krunner.service.in new file mode 100644 --- /dev/null +++ b/krunner/plasma-krunner.service.in @@ -0,0 +1,10 @@ +[Unit] +Description=KRunner + +[Service] +ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/krunner +KillMode=process +Type=dbus +BusName=org.kde.krunner +TimeoutSec=5sec +Slice=background.slice diff --git a/ksmserver/CMakeLists.txt b/ksmserver/CMakeLists.txt --- a/ksmserver/CMakeLists.txt +++ b/ksmserver/CMakeLists.txt @@ -71,3 +71,5 @@ ########### install files ############### install( FILES org.kde.KSMServerInterface.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR}) + +ecm_install_configured_files(TEMPLATES plasma-ksmserver.service.in DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) diff --git a/ksmserver/plasma-ksmserver.service.in b/ksmserver/plasma-ksmserver.service.in new file mode 100644 --- /dev/null +++ b/ksmserver/plasma-ksmserver.service.in @@ -0,0 +1,13 @@ +[Unit] +Description=KDE Session Management Server +Wants=plasma-kcminit.service + +[Service] +ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/ksmserver +# This magic minus sign means don't fail if exit code is non-zero... +ExecStartPost=-@QtBinariesDir@/qdbus org.kde.KSplash /KSplash org.kde.KSplash.setStage ksmserver +BusName=org.kde.ksmserver +Slice=session.slice + +[Install] +WantedBy=plasma-core.target diff --git a/ksmserver/server.cpp b/ksmserver/server.cpp --- a/ksmserver/server.cpp +++ b/ksmserver/server.cpp @@ -95,6 +95,8 @@ #include "kscreenlocker_interface.h" #include "kwinsession_interface.h" +#include "../config-workspace.h" + KSMServer* the_server = nullptr; KSMServer* KSMServer::self() diff --git a/login-sessions/plasmawayland-dev.desktop.cmake b/login-sessions/plasmawayland-dev.desktop.cmake --- a/login-sessions/plasmawayland-dev.desktop.cmake +++ b/login-sessions/plasmawayland-dev.desktop.cmake @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=dbus-run-session @CMAKE_INSTALL_FULL_LIBEXECDIR@/startplasma-dev.sh -wayland +Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/startplasma-dev.sh -wayland DesktopNames=KDE Name=Plasma (Development, Wayland ${CMAKE_INSTALL_FULL_BINDIR}) Name[ast]=Plasma (Desendolcu, Wayland ${CMAKE_INSTALL_FULL_BINDIR}) diff --git a/login-sessions/plasmawayland.desktop.cmake b/login-sessions/plasmawayland.desktop.cmake --- a/login-sessions/plasmawayland.desktop.cmake +++ b/login-sessions/plasmawayland.desktop.cmake @@ -1,5 +1,5 @@ [Desktop Entry] -Exec=dbus-run-session ${CMAKE_INSTALL_FULL_BINDIR}/startplasma-wayland +Exec=${CMAKE_INSTALL_FULL_BINDIR}/startplasma-wayland TryExec=${CMAKE_INSTALL_FULL_BINDIR}/startplasma-wayland DesktopNames=KDE Name=Plasma (Wayland) diff --git a/login-sessions/startplasma-dev.sh.cmake b/login-sessions/startplasma-dev.sh.cmake --- a/login-sessions/startplasma-dev.sh.cmake +++ b/login-sessions/startplasma-dev.sh.cmake @@ -2,4 +2,11 @@ source @CMAKE_INSTALL_FULL_LIBEXECDIR@/plasma-dev-prefix.sh +# This is a bit of a hack done because systemd starts in pam, and we only set our dev paths after all that is complete +# This copies everything into a transient runtime directory that systemd reads and reloads the units + +mkdir -p "$XDG_RUNTIME_DIR/systemd/user.control" +command cp -r @KDE_INSTALL_FULL_SYSTEMDUSERUNITDIR@/* $XDG_RUNTIME_DIR/systemd/user.control +systemctl --user daemon-reload + startplasma$@ diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -92,6 +92,8 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.plasmashell.desktop DESTINATION ${KDE_INSTALL_AUTOSTARTDIR}) install( FILES dbus/org.kde.PlasmaShell.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR} ) +ecm_install_configured_files(TEMPLATES plasma-plasmashell.service.in @ONLY DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) + install(FILES scripting/plasma-layouttemplate.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) diff --git a/shell/org.kde.plasmashell.desktop.cmake b/shell/org.kde.plasmashell.desktop.cmake --- a/shell/org.kde.plasmashell.desktop.cmake +++ b/shell/org.kde.plasmashell.desktop.cmake @@ -52,10 +52,12 @@ Name[zh_TW]=Plasma 桌面工作空間 Type=Application X-KDE-StartupNotify=false +X-KDE-HiddenUnderSystemd=true X-DBUS-ServiceName=org.kde.plasmashell OnlyShowIn=KDE; X-KDE-autostart-phase=0 Icon=plasma NoDisplay=true +X-systemd-hidden=true X-KDE-Wayland-Interfaces=org_kde_plasma_window_management,org_kde_kwin_keystate diff --git a/shell/plasma-plasmashell.service.in b/shell/plasma-plasmashell.service.in new file mode 100644 --- /dev/null +++ b/shell/plasma-plasmashell.service.in @@ -0,0 +1,15 @@ +[Unit] +Description=KDE Plasma Workspace +Wants=plasma-ksmserver.service plasma-kcminit.service + +[Service] +ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/plasmashell --no-respawn +Restart=on-failure +KillMode=process +Type=dbus +BusName=org.kde.plasmashell +Slice=session.slice +TimeoutSec=5sec + +[Install] +WantedBy=plasma-core.target diff --git a/startkde/CMakeLists.txt b/startkde/CMakeLists.txt --- a/startkde/CMakeLists.txt +++ b/startkde/CMakeLists.txt @@ -37,3 +37,9 @@ install(TARGETS startplasma-wayland ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS startplasma-waylandsession DESTINATION ${KDE_INSTALL_LIBEXECDIR}) install(PROGRAMS plasma-sourceenv.sh DESTINATION ${KDE_INSTALL_LIBEXECDIR}) + +ecm_install_configured_files(TEMPLATES plasma-ksplash-ready.service.in @ONLY + DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) + +install(FILES plasma-core@.target DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) +install(FILES plasma-workspace@.target DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) diff --git a/startkde/kcminit/CMakeLists.txt b/startkde/kcminit/CMakeLists.txt --- a/startkde/kcminit/CMakeLists.txt +++ b/startkde/kcminit/CMakeLists.txt @@ -32,6 +32,9 @@ qt5_add_dbus_interface(kcminit_startup_KDEINIT_SRCS ${klauncher_xml} klauncher_iface) kf5_add_kdeinit_executable( kcminit_startup ${kcminit_startup_KDEINIT_SRCS}) +ecm_install_configured_files(TEMPLATES plasma-kcminit-phase1.service.in plasma-kcminit.service.in + DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) + target_link_libraries(kdeinit_kcminit_startup Qt5::Core Qt5::Gui Qt5::DBus KF5::CoreAddons KF5::Service KF5::I18n PW::KWorkspace) if (XCB_XCB_FOUND) target_link_libraries(kdeinit_kcminit_startup XCB::XCB) diff --git a/startkde/kcminit/plasma-kcminit-phase1.service.in b/startkde/kcminit/plasma-kcminit-phase1.service.in new file mode 100644 --- /dev/null +++ b/startkde/kcminit/plasma-kcminit-phase1.service.in @@ -0,0 +1,9 @@ +[Unit] +Description=KDE Configuration Module Initialization (Phase 1) +Requires=kcminit.service +After=plasma-kcminit.service plasma-kded.service + +[Service] +Type=oneshot +ExecStart=@QtBinariesDir@/qdbus org.kde.kcminit /kcminit org.kde.KCMInit.runPhase1 +Slice=session.slice diff --git a/startkde/kcminit/plasma-kcminit.service.in b/startkde/kcminit/plasma-kcminit.service.in new file mode 100644 --- /dev/null +++ b/startkde/kcminit/plasma-kcminit.service.in @@ -0,0 +1,11 @@ +[Unit] +Description=KDE Config Module Initialization + +[Service] +ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/kcminit_startup +Restart=no +Type=forking +Slice=session.slice + +[Install] +Alias=plasma-workspace.service diff --git a/startkde/plasma-core@.target b/startkde/plasma-core@.target new file mode 100644 --- /dev/null +++ b/startkde/plasma-core@.target @@ -0,0 +1,5 @@ +[Unit] +Description=KDE Plasma Workspace Core +Wants=plasma-plasmashell.service plasma-kwin_%i.service plasma-kcminit.service plasma-kded.service plasma-kcminit-phase1.service +Requires=plasma-ksmserver.service +BindsTo=plasma-ksmserver.service diff --git a/startkde/plasma-ksplash-ready.service.in b/startkde/plasma-ksplash-ready.service.in new file mode 100644 --- /dev/null +++ b/startkde/plasma-ksplash-ready.service.in @@ -0,0 +1,9 @@ +[Unit] +Description=KSplash "ready" Stage +Wants=plasma-core.target +After=plasma-core.target + +[Service] +Type=oneshot +ExecStart=-@QtBinariesDir@/qdbus org.kde.KSplash /KSplash org.kde.KSplash.setStage ready +Slice=session.slice diff --git a/startkde/plasma-workspace@.target b/startkde/plasma-workspace@.target new file mode 100644 --- /dev/null +++ b/startkde/plasma-workspace@.target @@ -0,0 +1,5 @@ +[Unit] +Description=KDE Plasma Workspace +Requires=plasma-core@%i.target plasma-ksplash-ready.service +Wants=xdg-desktop.target +After=plasma-core.target diff --git a/startkde/startplasma.cpp b/startkde/startplasma.cpp --- a/startkde/startplasma.cpp +++ b/startkde/startplasma.cpp @@ -35,6 +35,9 @@ #include "startplasma.h" +#include "../config-workspace.h" + + QTextStream out(stderr); void messageBox(const QString &text) @@ -349,22 +352,9 @@ // If the session should be locked from the start (locked autologin), // lock now and do the rest of the KDE startup underneath the locker. - - QStringList plasmaSessionOptions; - if (wayland) { - plasmaSessionOptions << QStringLiteral("--no-lockscreen"); - } else { - if (desktopLockedAtStart) { - plasmaSessionOptions << QStringLiteral("--lockscreen"); - } - } - bool rc = true; QEventLoop e; - QProcess startPlasmaSession; - startPlasmaSession.setProcessChannelMode(QProcess::ForwardedChannels); - QDBusServiceWatcher serviceWatcher; serviceWatcher.setConnection(QDBusConnection::sessionBus()); @@ -374,15 +364,6 @@ serviceWatcher.addWatchedService(QStringLiteral("org.kde.shutdown")); serviceWatcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration); - QObject::connect(&startPlasmaSession, QOverload::of(&QProcess::finished), [&rc, &e](int exitCode, QProcess::ExitStatus) { - if (exitCode == 255) { - // Startup error - messageBox(QStringLiteral("startkde: Could not start ksmserver. Check your installation.\n")); - rc = false; - e.quit(); - } - }); - QObject::connect(&serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, [&]() { const QStringList watchedServices = serviceWatcher.watchedServices(); bool plasmaSessionRunning = std::any_of(watchedServices.constBegin(), watchedServices.constEnd(), [](const QString &service) { @@ -393,8 +374,48 @@ } }); +#ifndef PLASMA_SYSTEMD_BOOT + QProcess startPlasmaSession; + + QStringList plasmaSessionOptions; + if (wayland) { + plasmaSessionOptions << QStringLiteral("--no-lockscreen"); + } else { + if (desktopLockedAtStart) { + plasmaSessionOptions << QStringLiteral("--lockscreen"); + } + } + + startPlasmaSession.setProcessChannelMode(QProcess::ForwardedChannels); + QObject::connect(&startPlasmaSession, QOverload::of(&QProcess::finished), [&rc, &e](int exitCode, QProcess::ExitStatus) { + if (exitCode == 255) { + // Startup error + messageBox(QStringLiteral("startkde: Could not start ksmserver. Check your installation.\n")); + rc = false; + e.quit(); + } + }); + startPlasmaSession.start(QStringLiteral(CMAKE_INSTALL_FULL_BINDIR "/plasma_session"), plasmaSessionOptions); - e.exec(); + rc = startPlasmaSession.waitForStarted(); +#else + + const QString platform = wayland ? QStringLiteral("wayland") : QStringLiteral("x11"); + + auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), + QStringLiteral("/org/freedesktop/systemd1"), + QStringLiteral("org.freedesktop.systemd1.Manager"), + QStringLiteral("StartUnit")); + msg << QStringLiteral("plasma-workspace@%1.target").arg(platform) << QStringLiteral("fail"); + auto reply = QDBusConnection::sessionBus().call(msg); + if (reply.type() == QDBusMessage::ErrorMessage) { + rc = false; + } +#endif + + if (rc) { + e.exec(); + } return rc; } diff --git a/xembed-sni-proxy/CMakeLists.txt b/xembed-sni-proxy/CMakeLists.txt --- a/xembed-sni-proxy/CMakeLists.txt +++ b/xembed-sni-proxy/CMakeLists.txt @@ -64,3 +64,4 @@ install(TARGETS xembedsniproxy ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES xembedsniproxy.desktop DESTINATION ${KDE_INSTALL_AUTOSTARTDIR}) +ecm_install_configured_files(TEMPLATES plasma-xembedsniproxy.service.in @ONLY DESTINATION ${SYSTEMD_USER_UNIT_INSTALL_DIR}) diff --git a/xembed-sni-proxy/plasma-xembedsniproxy.service.in b/xembed-sni-proxy/plasma-xembedsniproxy.service.in new file mode 100644 --- /dev/null +++ b/xembed-sni-proxy/plasma-xembedsniproxy.service.in @@ -0,0 +1,13 @@ +[Unit] +Description=Handle legacy xembed system tray icons + +[Service] +ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/xembedsniproxy +Restart=on-failure +KillMode=process +Type=simple +Slice=background.slice +TimeoutSec=5sec + +[Install] +WantedBy=plasma-workspace.target diff --git a/xembed-sni-proxy/xembedsniproxy.desktop b/xembed-sni-proxy/xembedsniproxy.desktop --- a/xembed-sni-proxy/xembedsniproxy.desktop +++ b/xembed-sni-proxy/xembedsniproxy.desktop @@ -44,3 +44,4 @@ X-KDE-StartupNotify=false OnlyShowIn=KDE; X-KDE-autostart-phase=0 +X-systemd-hidden=true