From e770d59492814dc510f6659c36eb9859ae6d0946 Mon Sep 17 00:00:00 2001 From: April & May Date: Tue, 5 Aug 2025 05:04:45 +0800 Subject: [PATCH] feat: Support VT switching 1. Remove seatd-dde.service, use system provided seatd service; 2. Record VT number per session; 3. Add private wayland protocol treeland-private-protocol.xml for IPC, implement wayland event for acquiring VT control and switching VT; 4. Listen to VT acquire & release display signal and activate & deactivate treeland correspondingly. --- .reuse/dep5 | 2 + CMakeLists.txt | 3 + debian/control | 1 + nix/default.nix | 2 + services/CMakeLists.txt | 3 - services/ddm.service.in | 4 +- services/seatd-dde.service.in | 62 ---------- src/common/VirtualTerminal.cpp | 30 +++-- src/common/VirtualTerminal.h | 3 + src/daemon/CMakeLists.txt | 12 ++ src/daemon/DaemonApp.cpp | 7 ++ src/daemon/DaemonApp.h | 3 + src/daemon/Display.cpp | 4 +- src/daemon/DisplayManager.cpp | 21 +++- src/daemon/DisplayManager.h | 8 +- src/daemon/SocketServer.cpp | 6 + src/daemon/TreelandConnector.cpp | 187 +++++++++++++++++++++++++++++++ src/daemon/TreelandConnector.h | 29 +++++ 18 files changed, 306 insertions(+), 81 deletions(-) delete mode 100644 services/seatd-dde.service.in create mode 100644 src/daemon/TreelandConnector.cpp create mode 100644 src/daemon/TreelandConnector.h diff --git a/.reuse/dep5 b/.reuse/dep5 index e970f9b..4a5d7ae 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -138,6 +138,8 @@ Files: src/daemon/SeatManager.h src/daemon/SocketServer.cpp src/daemon/SocketServer.h + src/daemon/TreelandConnector.cpp + src/daemon/TreelandConnector.h src/daemon/Utils.h src/daemon/WaylandDisplayServer.cpp src/daemon/WaylandDisplayServer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index dbe4600..c9c1414 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,9 @@ find_package(XCB REQUIRED) # XKB find_package(XKB REQUIRED) +# TreelandProtocols +find_package(TreelandProtocols REQUIRED) + find_package(Qt6 CONFIG REQUIRED Core DBus Gui Qml Quick QuickControls2 LinguistTools Test QuickTest) qt_standard_project_setup(REQUIRES 6.6) diff --git a/debian/control b/debian/control index f065b12..2e6c183 100644 --- a/debian/control +++ b/debian/control @@ -19,6 +19,7 @@ Build-Depends: debhelper-compat (= 13), qt6-wayland, qt6-wayland-dev, qt6-wayland-private-dev, + treeland-protocols, systemd [linux-any], Standards-Version: 4.6.0 Section: libs diff --git a/nix/default.nix b/nix/default.nix index 403718c..d8bef64 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -11,6 +11,7 @@ , pixman , pam , libxcrypt +, treeland-protocols }: stdenv.mkDerivation (finalAttrs: { @@ -51,6 +52,7 @@ stdenv.mkDerivation (finalAttrs: { pixman pam libxcrypt + treeland-protocols ]; cmakeFlags = [ diff --git a/services/CMakeLists.txt b/services/CMakeLists.txt index c8bee4d..d584fae 100644 --- a/services/CMakeLists.txt +++ b/services/CMakeLists.txt @@ -2,9 +2,6 @@ if(SYSTEMD_FOUND) configure_file(ddm.service.in ddm.service) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ddm.service" DESTINATION "${SYSTEMD_SYSTEM_UNIT_DIR}") - configure_file(seatd-dde.service.in seatd-dde.service) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/seatd-dde.service" DESTINATION "${SYSTEMD_SYSTEM_UNIT_DIR}") - configure_file(ddm-sysuser.conf.in ddm-sysuser.conf) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/ddm-sysuser.conf" DESTINATION "${SYSTEMD_SYSUSERS_DIR}" RENAME dde.conf) endif() diff --git a/services/ddm.service.in b/services/ddm.service.in index 143bc7b..6231442 100644 --- a/services/ddm.service.in +++ b/services/ddm.service.in @@ -7,8 +7,8 @@ PartOf=graphical.target StartLimitIntervalSec=30 StartLimitBurst=2 -Requires=seatd-dde.service -Before=seatd-dde.service +Requires=seatd.service +Before=seatd.service [Service] ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/ddm diff --git a/services/seatd-dde.service.in b/services/seatd-dde.service.in deleted file mode 100644 index a0f9358..0000000 --- a/services/seatd-dde.service.in +++ /dev/null @@ -1,62 +0,0 @@ -[Unit] -Description=Seat management daemon for DDE -Documentation=man:seatd(1) -Conflicts=seatd.service - -[Service] -Type=simple -Environment=SEATD_VTBOUND=0 -ExecStart=seatd -u dde -g dde -Restart=always -RestartSec=1 - -# Filesystem lockdown -ProtectHome=true -ProtectSystem=strict -ProtectKernelTunables=true -ProtectControlGroups=true -PrivateTmp=true -ProtectProc=invisible -ProcSubset=pid -UMask=0077 - -# Privilege escalation -NoNewPrivileges=true -RestrictSUIDSGID=true - -# Network -PrivateNetwork=true -IPAddressDeny=any - -# System call interfaces -SystemCallFilter=@system-service -SystemCallFilter=~@resources -SystemCallErrorNumber=EPERM -SystemCallArchitectures=native - -# Kernel -ProtectKernelLogs=true -ProtectKernelModules=true -LockPersonality=true - -# Namespaces -RestrictNamespaces=true - -# Service capabilities -CapabilityBoundingSet=CAP_SYS_ADMIN CAP_CHOWN CAP_SYS_TTY_CONFIG CAP_DAC_OVERRIDE -RestrictAddressFamilies=AF_UNIX -RestrictRealtime=true -MemoryDenyWriteExecute=true -ProtectClock=true -ProtectHostname=true - -# Devices -DevicePolicy=strict -DeviceAllow=char-/dev/console rw -DeviceAllow=char-drm rw -DeviceAllow=char-input rw -DeviceAllow=char-tty rw -DeviceAllow=/dev/null rw - -[Install] -WantedBy=multi-user.target diff --git a/src/common/VirtualTerminal.cpp b/src/common/VirtualTerminal.cpp index 38e79e2..811fdc1 100644 --- a/src/common/VirtualTerminal.cpp +++ b/src/common/VirtualTerminal.cpp @@ -75,19 +75,30 @@ namespace DDM { } #endif + std::function onAcquireFunction = nullptr; + std::function onReleaseFunction = nullptr; + static void onAcquireDisplay([[maybe_unused]] int signal) { - int fd = open(defaultVtPath, O_RDWR | O_NOCTTY); - ioctl(fd, VT_RELDISP, VT_ACKACQ); - close(fd); + if (onAcquireFunction) { + onAcquireFunction(); + } else { + int fd = open(defaultVtPath, O_RDWR | O_NOCTTY); + ioctl(fd, VT_RELDISP, VT_ACKACQ); + close(fd); + } } static void onReleaseDisplay([[maybe_unused]] int signal) { - int fd = open(defaultVtPath, O_RDWR | O_NOCTTY); - ioctl(fd, VT_RELDISP, 1); - close(fd); + if (onReleaseFunction) { + onReleaseFunction(); + } else { + int fd = open(defaultVtPath, O_RDWR | O_NOCTTY); + ioctl(fd, VT_RELDISP, 1); + close(fd); + } } - static bool handleVtSwitches(int fd) { + bool handleVtSwitches(int fd) { vt_mode setModeRequest { }; bool ok = true; @@ -254,5 +265,10 @@ namespace DDM { if (vtFd != -1) close(vtFd); } + + void setVtSignalHandler(std::function onAcquireDisplay, std::function onReleaseDisplay) { + onAcquireFunction = onAcquireDisplay; + onReleaseFunction = onReleaseDisplay; + } } } diff --git a/src/common/VirtualTerminal.h b/src/common/VirtualTerminal.h index c9a59e4..b5251ab 100644 --- a/src/common/VirtualTerminal.h +++ b/src/common/VirtualTerminal.h @@ -25,9 +25,12 @@ namespace DDM { namespace VirtualTerminal { QString path(int vt); + int getVtActive(int fd); + bool handleVtSwitches(int fd); int currentVt(); int setUpNewVt(); void jumpToVt(int vt, bool vt_auto); + void setVtSignalHandler(std::function onAcquireDisplay, std::function onReleaseDisplay); } } diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index 341054b..56e0816 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -3,6 +3,15 @@ include_directories( "${LIBXCB_INCLUDE_DIR}" ) +pkg_search_module(WAYLAND REQUIRED IMPORTED_TARGET wayland-client) + +add_custom_target(treeland-ddm ALL + COMMAND + wayland-scanner client-header < ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-ddm-v1.xml > ${CMAKE_CURRENT_BINARY_DIR}/treeland-ddm-v1.h + COMMAND + wayland-scanner private-code < ${TREELAND_PROTOCOLS_DATA_DIR}/treeland-ddm-v1.xml > ${CMAKE_CURRENT_BINARY_DIR}/treeland-ddm-v1.c +) + configure_file(config.h.in config.h IMMEDIATE @ONLY) set(DAEMON_SOURCES DaemonApp.cpp @@ -14,6 +23,7 @@ set(DAEMON_SOURCES Seat.cpp SeatManager.cpp SocketServer.cpp + TreelandConnector.cpp XorgDisplayServer.cpp XorgUserDisplayServer.cpp XorgUserDisplayServer.h @@ -21,6 +31,7 @@ set(DAEMON_SOURCES WaylandDisplayServer.h SingleWaylandDisplayServer.h SingleWaylandDisplayServer.cpp + treeland-ddm-v1.c ) qt_add_dbus_adaptor(DAEMON_SOURCES "${CMAKE_SOURCE_DIR}/data/interfaces/org.freedesktop.DisplayManager.xml" "DisplayManager.h" DDM::DisplayManager) @@ -57,6 +68,7 @@ target_link_libraries(ddm Qt${QT_MAJOR_VERSION}::Network Qt${QT_MAJOR_VERSION}::Qml ${LIBXCB_LIBRARIES} + PkgConfig::WAYLAND ) if(JOURNALD_FOUND) diff --git a/src/daemon/DaemonApp.cpp b/src/daemon/DaemonApp.cpp index 961ef38..161fef9 100644 --- a/src/daemon/DaemonApp.cpp +++ b/src/daemon/DaemonApp.cpp @@ -25,6 +25,7 @@ #include "PowerManager.h" #include "SeatManager.h" #include "SignalHandler.h" +#include "TreelandConnector.h" #include "MessageHandler.h" @@ -85,6 +86,8 @@ namespace DDM { // quit when SIGINT, SIGTERM received connect(m_signalHandler, &SignalHandler::sigintReceived, this, &DaemonApp::quit); connect(m_signalHandler, &SignalHandler::sigtermReceived, this, &DaemonApp::quit); + + m_treelandConnector = new TreelandConnector(); // log message qDebug() << "Starting..."; @@ -117,6 +120,10 @@ namespace DDM { return m_signalHandler; } + TreelandConnector *DaemonApp::treelandConnector() const { + return m_treelandConnector; + } + int DaemonApp::newSessionId() { return m_lastSessionId++; } diff --git a/src/daemon/DaemonApp.h b/src/daemon/DaemonApp.h index 1676a1a..c5620f7 100644 --- a/src/daemon/DaemonApp.h +++ b/src/daemon/DaemonApp.h @@ -30,6 +30,7 @@ namespace DDM { class PowerManager; class SeatManager; class SignalHandler; + class TreelandConnector; class DaemonApp : public QCoreApplication { Q_OBJECT @@ -48,6 +49,7 @@ namespace DDM { PowerManager *powerManager() const; SeatManager *seatManager() const; SignalHandler *signalHandler() const; + TreelandConnector *treelandConnector() const; void backToNormal(); @@ -64,6 +66,7 @@ namespace DDM { PowerManager *m_powerManager { nullptr }; SeatManager *m_seatManager { nullptr }; SignalHandler *m_signalHandler { nullptr }; + TreelandConnector *m_treelandConnector { nullptr }; }; } diff --git a/src/daemon/Display.cpp b/src/daemon/Display.cpp index 0a20a05..214e20f 100644 --- a/src/daemon/Display.cpp +++ b/src/daemon/Display.cpp @@ -138,6 +138,8 @@ namespace DDM { m_displayServer = new SingleWaylandDisplayServer(m_socketServer, this); m_greeter->setDisplayServerCommand(mainConfig.Single.CompositorCommand.get()); m_greeter->setSingleMode(); + // Record current VT as ddm user session + DaemonApp::instance()->displayManager()->AddSession({}, seat()->name(), "ddm", static_cast(VirtualTerminal::currentVt())); break; } @@ -537,7 +539,7 @@ namespace DDM { // session id { const QString sessionId = QStringLiteral("Session%1").arg(daemonApp->newSessionId()); - daemonApp->displayManager()->AddSession(sessionId, seat()->name(), user); + daemonApp->displayManager()->AddSession(sessionId, seat()->name(), user, auth->tty()); env.insert(QStringLiteral("XDG_SESSION_PATH"), daemonApp->displayManager()->sessionPath(sessionId)); auth->setSessionId(sessionId); } diff --git a/src/daemon/DisplayManager.cpp b/src/daemon/DisplayManager.cpp index 740ff40..2cf3c0a 100644 --- a/src/daemon/DisplayManager.cpp +++ b/src/daemon/DisplayManager.cpp @@ -26,6 +26,7 @@ #include "displaymanageradaptor.h" #include "seatadaptor.h" #include "sessionadaptor.h" +#include "VirtualTerminal.h" const QString DISPLAYMANAGER_SERVICE = QStringLiteral("org.freedesktop.DisplayManager"); const QString DISPLAYMANAGER_PATH = QStringLiteral("/org/freedesktop/DisplayManager"); @@ -132,9 +133,9 @@ namespace DDM { } } - void DisplayManager::AddSession(const QString &name, const QString &seat, const QString &user) { + void DisplayManager::AddSession(const QString &name, const QString &seat, const QString &user, const int &vtnr) { // create session object - DisplayManagerSession *session = new DisplayManagerSession(name, seat, user, this); + DisplayManagerSession *session = new DisplayManagerSession(name, seat, user, vtnr, this); // add to the list m_sessions << session; @@ -178,6 +179,14 @@ namespace DDM { } } + const QString DisplayManager::findUserByVt(int vtnr) { + for (auto session : m_sessions) { + if (vtnr == session->VTNr()) + return session->User(); + } + return QString(); + } + DisplayManagerSeat::DisplayManagerSeat(const QString &name, QObject *parent) : QObject(parent), m_name(name), m_path(DISPLAYMANAGER_SEAT_PATH + name.mid(4)) { // create adaptor @@ -217,8 +226,8 @@ namespace DDM { return daemonApp->displayManager()->Sessions(this); } - DisplayManagerSession::DisplayManagerSession(const QString &name, const QString &seat, const QString &user, QObject *parent) - : QObject(parent), m_name(name), m_path(DISPLAYMANAGER_SESSION_PATH + name.mid(7)), m_seat(seat), m_user(user) { + DisplayManagerSession::DisplayManagerSession(const QString &name, const QString &seat, const QString &user, const int &vtnr, QObject *parent) + : QObject(parent), m_name(name), m_path(DISPLAYMANAGER_SESSION_PATH + name.mid(7)), m_seat(seat), m_user(user), m_vtnr(vtnr) { // create adaptor new SessionAdaptor(this); @@ -240,6 +249,10 @@ namespace DDM { return m_seat; } + const int &DisplayManagerSession::VTNr() const { + return m_vtnr; + } + void DisplayManagerSession::Lock() { // TODO: IMPLEMENT } diff --git a/src/daemon/DisplayManager.h b/src/daemon/DisplayManager.h index ee52e0d..fd918d6 100644 --- a/src/daemon/DisplayManager.h +++ b/src/daemon/DisplayManager.h @@ -60,10 +60,12 @@ namespace DDM { QString AuthInfo() const; QString LastActivatedUser() const; + const QString findUserByVt(int vtnr); + public slots: void AddSeat(const QString &name); void RemoveSeat(const QString &name); - void AddSession(const QString &name, const QString &seat, const QString &user); + void AddSession(const QString &name, const QString &seat, const QString &user, const int &vtnr); void RemoveSession(const QString &name); void setLastSession(const QString &session); void setAuthInfo(const QString &authSocket); @@ -124,12 +126,13 @@ namespace DDM { Q_PROPERTY(QDBusObjectPath Seat READ SeatPath) Q_PROPERTY(QString UserName READ User) public: - DisplayManagerSession(const QString &name, const QString &seat, const QString &user, QObject *parent = 0); + DisplayManagerSession(const QString &name, const QString &seat, const QString &user, const int &vtnr, QObject *parent = 0); const QString &Name() const; const QString &Path() const; const QString &Seat() const; const QString &User() const; + const int &VTNr() const; void Lock(); @@ -140,6 +143,7 @@ namespace DDM { QString m_path; QString m_seat; QString m_user; + int m_vtnr; }; } diff --git a/src/daemon/SocketServer.cpp b/src/daemon/SocketServer.cpp index 10a850d..7724d36 100644 --- a/src/daemon/SocketServer.cpp +++ b/src/daemon/SocketServer.cpp @@ -24,6 +24,7 @@ #include "Messages.h" #include "PowerManager.h" #include "SocketWriter.h" +#include "TreelandConnector.h" #include "Utils.h" #include @@ -124,6 +125,11 @@ namespace DDM { // log message qDebug() << "Message received from greeter: Connect"; + // Connect wayland socket + QString socketPath; + input >> socketPath; + daemonApp->treelandConnector()->connect(socketPath); + // send capabilities SocketWriter(socket) << quint32(DaemonMessages::Capabilities) << quint32(daemonApp->powerManager()->capabilities()); diff --git a/src/daemon/TreelandConnector.cpp b/src/daemon/TreelandConnector.cpp new file mode 100644 index 0000000..0c9daee --- /dev/null +++ b/src/daemon/TreelandConnector.cpp @@ -0,0 +1,187 @@ +// Copyright (C) 2025 April Lu . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "TreelandConnector.h" +#include "DaemonApp.h" +#include "DisplayManager.h" +#include "VirtualTerminal.h" +#include "treeland-ddm-v1.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace DDM { + +// Virtural Terminal helper from VirturalTerminal.h + +static const char *defaultVtPath = "/dev/tty0"; + +static void onAcquireDisplay() { + int fd = open(defaultVtPath, O_RDWR | O_NOCTTY); + ioctl(fd, VT_RELDISP, VT_ACKACQ); + int vtnr = VirtualTerminal::getVtActive(fd); + close(fd); + auto user = daemonApp->displayManager()->findUserByVt(vtnr); + if (!user.isEmpty()) { + qDebug("Activate session at VT %d for user %s", vtnr, qPrintable(user)); + daemonApp->treelandConnector()->switchToUser(user); + daemonApp->treelandConnector()->activateSession(); + } +} + +static void onReleaseDisplay() { + int fd = open(defaultVtPath, O_RDWR | O_NOCTTY); + ioctl(fd, VT_RELDISP, 1); + close(fd); + int activeVtFd = open(defaultVtPath, O_RDWR | O_NOCTTY); + int activeVt = VirtualTerminal::getVtActive(activeVtFd); + auto user = daemonApp->displayManager()->findUserByVt(activeVt); + qDebug("Next VT: %d, user: %s", activeVt, qPrintable(user)); + if (user.isEmpty()) { + // We must switch Treeland to greeter mode before we switch back to it, + // or it will get stuck. + daemonApp->treelandConnector()->switchToGreeter(); + daemonApp->treelandConnector()->deactivateSession(); + } else { + // If user is not empty, it means the switching can be issued by + // ddm-helper. It uses VT signals from VirtualTerminal.h, + // which is not what we want, so we should acquire VT control here. + VirtualTerminal::handleVtSwitches(activeVtFd); + } + close(activeVtFd); +} + +// TreelandConnector + +TreelandConnector::TreelandConnector() : QObject(nullptr) { + VirtualTerminal::setVtSignalHandler(onAcquireDisplay, onReleaseDisplay); +} + +TreelandConnector::~TreelandConnector() { + delete m_notifier; + wl_display_disconnect(m_display); +} + +bool TreelandConnector::isConnected() { + return m_ddm; +} + +void TreelandConnector::setPrivateObject(struct treeland_ddm *ddm) { + m_ddm = ddm; +} + +// Event implementation + +void switchToVt([[maybe_unused]] void *data, [[maybe_unused]] struct treeland_ddm *ddm, int32_t vtnr) { + int fd = open(qPrintable(VirtualTerminal::path(vtnr)), O_RDWR | O_NOCTTY); + if (ioctl(fd, VT_ACTIVATE, vtnr) < 0) + qWarning("Failed to switch to VT %d: %s", vtnr, strerror(errno)); + close(fd); +} + +void acquireVt([[maybe_unused]] void *data, [[maybe_unused]] struct treeland_ddm *ddm, int32_t vtnr) { + int fd = open(qPrintable(VirtualTerminal::path(vtnr)), O_RDWR | O_NOCTTY); + VirtualTerminal::handleVtSwitches(fd); + close(fd); +} + +const struct treeland_ddm_listener treelandDDMListener { + .switch_to_vt = switchToVt, + .acquire_vt = acquireVt, +}; + +// wayland object binding + +void registerGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, "treeland_ddm") == 0) { + auto connector = static_cast(data); + auto ddm = static_cast( + wl_registry_bind(registry, name, &treeland_ddm_interface, version) + ); + treeland_ddm_add_listener(ddm, &treelandDDMListener, connector); + connector->setPrivateObject(ddm); + qDebug("Connected to treeland_ddm global object"); + } +} + +void removeGlobal([[maybe_unused]] void *data, [[maybe_unused]] struct wl_registry *registry, [[maybe_unused]] uint32_t name) { + // Do not deregister the global object (set m_priv to null) here, + // as wlroots will send global_remove event when session deactivated, + // which is not what we want. The connection will be preserved after that. +} + +const struct wl_registry_listener registryListener { + .global = registerGlobal, + .global_remove = removeGlobal, +}; + +void TreelandConnector::connect(QString socketPath) { + m_display = wl_display_connect(qPrintable(socketPath)); + auto registry = wl_display_get_registry(m_display); + + wl_registry_add_listener(registry, ®istryListener, this); + + wl_display_roundtrip(m_display); + + while (wl_display_prepare_read(m_display) != 0) + wl_display_dispatch_pending(m_display); + wl_display_flush(m_display); + m_notifier = new QSocketNotifier(wl_display_get_fd(m_display), QSocketNotifier::Read); + QObject::connect(m_notifier, &QSocketNotifier::activated, this, [this] { + wl_display_read_events(m_display); + while (wl_display_prepare_read(m_display) != 0) + wl_display_dispatch_pending(m_display); + wl_display_flush(m_display); + }); +} + +// Request wrapper + +void TreelandConnector::switchToGreeter() { + if (isConnected()) { + treeland_ddm_switch_to_greeter(m_ddm); + wl_display_flush(m_display); + } else { + qWarning("Treeland is not connected when trying to call switchToGreeter"); + } +} + +void TreelandConnector::switchToUser(const QString username) { + if (isConnected()) { + treeland_ddm_switch_to_user(m_ddm, qPrintable(username)); + wl_display_flush(m_display); + } else { + qWarning("Treeland is not connected when trying to call switchToUser"); + } +} + +void TreelandConnector::activateSession() { + if (isConnected()) { + treeland_ddm_activate_session(m_ddm); + wl_display_flush(m_display); + } else { + qWarning("Treeland is not connected when trying to call activateSession"); + } +} + +void TreelandConnector::deactivateSession() { + if (isConnected()) { + treeland_ddm_deactivate_session(m_ddm); + wl_display_flush(m_display); + } else { + qWarning("Treeland is not connected when trying to call deactivateSession"); + } +} + +} diff --git a/src/daemon/TreelandConnector.h b/src/daemon/TreelandConnector.h new file mode 100644 index 0000000..c2b8fd9 --- /dev/null +++ b/src/daemon/TreelandConnector.h @@ -0,0 +1,29 @@ +// Copyright (C) 2025 April Lu . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include +#include + +struct wl_display; +struct treeland_ddm; + +namespace DDM { +class TreelandConnector : QObject { + Q_OBJECT +public: + TreelandConnector(); + ~TreelandConnector(); + bool isConnected(); + void setPrivateObject(struct treeland_ddm *ddm); + void connect(const QString socketPath); + + void switchToGreeter(); + void switchToUser(const QString username); + void activateSession(); + void deactivateSession(); +private: + struct wl_display *m_display { nullptr }; + QSocketNotifier *m_notifier { nullptr }; + struct treeland_ddm *m_ddm { nullptr }; +}; +}