From aecb5a71c0461c767c26bb1a14da30bdfd8313af Mon Sep 17 00:00:00 2001 From: April & May Date: Thu, 28 Aug 2025 11:13:19 +0800 Subject: [PATCH] fix: refine TTY switching 1. Add callback for disableRender, to ensure render is exactly disabled before DDM doing further actions; 2. Revoke all evdev devices before VT switch (at disableRender()), to prevent accidental input events during switch; 3. Refine logic of switchToUser, take care of showing lockscreen after switch; 4. Make event function args const --- src/modules/ddm/ddminterfacev1.cpp | 19 ++++++++++++++----- src/modules/ddm/ddminterfacev1.h | 4 ++-- src/seat/helper.cpp | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/modules/ddm/ddminterfacev1.cpp b/src/modules/ddm/ddminterfacev1.cpp index e8c07b1acd..5d96581926 100644 --- a/src/modules/ddm/ddminterfacev1.cpp +++ b/src/modules/ddm/ddminterfacev1.cpp @@ -23,8 +23,13 @@ static void switchToGreeter([[maybe_unused]] struct wl_client *client, [[maybe_u } static void switchToUser([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource, const char *username) { - if (strcmp(username, "ddm") != 0) { - Helper::instance()->userModel()->setCurrentUserName(QString(username)); + auto user = QString::fromLocal8Bit(username); + auto helper = Helper::instance(); + if (user == "ddm") { + helper->showLockScreen(false); + } else if (user != helper->userModel()->currentUserName()) { + helper->userModel()->setCurrentUserName(QString(username)); + helper->showLockScreen(false); } } @@ -40,8 +45,12 @@ static void enableRender([[maybe_unused]] struct wl_client *client, [[maybe_unus Helper::instance()->enableRender(); } -static void disableRender([[maybe_unused]] struct wl_client *client, [[maybe_unused]] struct wl_resource *resource) { +static void disableRender(struct wl_client *client, [[maybe_unused]] struct wl_resource *resource, uint32_t id) { Helper::instance()->disableRender(); + auto callback = wl_resource_create(client, &wl_callback_interface, 1, id); + auto serial = wl_display_get_serial(wl_client_get_display(client)); + wl_callback_send_done(callback, serial); + wl_resource_destroy(callback); } static const struct treeland_ddm_interface treeland_ddm_impl { @@ -110,7 +119,7 @@ wl_global *DDMInterfaceV1::global() const { // Event wrapper -void DDMInterfaceV1::switchToVt(int vtnr) { +void DDMInterfaceV1::switchToVt(const int vtnr) { auto ddm = static_cast(m_handle); if (isConnected()) treeland_ddm_send_switch_to_vt(ddm->resource, vtnr); @@ -118,7 +127,7 @@ void DDMInterfaceV1::switchToVt(int vtnr) { qCWarning(treelandCore) << "DDM is not conected when trying to call switchToVt"; } -void DDMInterfaceV1::acquireVt(int vtnr) { +void DDMInterfaceV1::acquireVt(const int vtnr) { auto ddm = static_cast(m_handle); if (isConnected()) treeland_ddm_send_acquire_vt(ddm->resource, vtnr); diff --git a/src/modules/ddm/ddminterfacev1.h b/src/modules/ddm/ddminterfacev1.h index 2eae63b57d..5bd796911b 100644 --- a/src/modules/ddm/ddminterfacev1.h +++ b/src/modules/ddm/ddminterfacev1.h @@ -12,8 +12,8 @@ class DDMInterfaceV1 : public Waylib::Server::WServerInterface { ~DDMInterfaceV1() override; QByteArrayView interfaceName() const override; bool isConnected() const; - void switchToVt(int vtnr); - void acquireVt(int vtnr); + void switchToVt(const int vtnr); + void acquireVt(const int vtnr); protected: void create(Waylib::Server::WServer *server) override; void destroy(Waylib::Server::WServer *server) override; diff --git a/src/seat/helper.cpp b/src/seat/helper.cpp index e358fb1a96..ed41ece2fd 100644 --- a/src/seat/helper.cpp +++ b/src/seat/helper.cpp @@ -104,6 +104,9 @@ #include #include +#include +#include +#include #define WLR_FRACTIONAL_SCALE_V1_VERSION 1 #define EXT_DATA_CONTROL_MANAGER_V1_VERSION 1 @@ -2205,4 +2208,17 @@ void Helper::enableRender() { void Helper::disableRender() { m_renderWindow->setRenderEnabled(false); + + // Revoke all evdev devices to prevent accidental events during switch + static const char prefix[] = "/dev/input/"; + static const int prefixLen = strlen(prefix); + struct wlr_session *session = m_backend->session()->handle(); + struct wlr_device *device = nullptr; + wl_list_for_each(device, &session->devices, link) { + char path[32]; + if (readlink(qPrintable(QStringLiteral("/proc/self/fd/%1").arg(device->fd)), path, 32) < 0) + qCWarning(treelandCore) << "Failed to read path of file descriptor " << device->fd; + else if (strncmp(prefix, path, prefixLen)) + ioctl(device->fd, EVIOCREVOKE, nullptr); + } }