From 3e543d2ce8ba64abb4d226dbb88c4513474501cf Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:07:36 -0500 Subject: [PATCH] core: Properly shutdown wl display (#7018) * correctly destroy wayland globals * properly shutdown and cleanup hyprland * appease the nitpick gods and some comments --- src/Compositor.cpp | 24 +++++---- src/Compositor.hpp | 1 + src/main.cpp | 6 +-- src/managers/KeybindManager.cpp | 2 +- src/managers/ProtocolManager.cpp | 54 +++++++++++++++++++++ src/managers/ProtocolManager.hpp | 1 + src/managers/eventLoop/EventLoopManager.cpp | 6 +++ src/protocols/GlobalShortcuts.cpp | 11 ++++- src/protocols/GlobalShortcuts.hpp | 7 ++- src/protocols/Screencopy.cpp | 9 +++- src/protocols/Screencopy.hpp | 21 ++++---- src/protocols/TextInputV1.cpp | 11 ++++- src/protocols/TextInputV1.hpp | 28 ++++++----- src/protocols/ToplevelExport.cpp | 9 +++- src/protocols/ToplevelExport.hpp | 23 ++++----- src/protocols/WaylandProtocol.cpp | 3 +- src/protocols/WaylandProtocol.hpp | 5 +- 17 files changed, 161 insertions(+), 60 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7caaa98a..36f483fd 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -43,7 +43,7 @@ int handleCritSignal(int signo, void* data) { Debug::log(LOG, "Hyprland received signal {}", signo); if (signo == SIGTERM || signo == SIGINT || signo == SIGKILL) - g_pCompositor->cleanup(); + g_pCompositor->stopCompositor(); return 0; } @@ -193,7 +193,8 @@ CCompositor::CCompositor() { } CCompositor::~CCompositor() { - cleanup(); + if (!m_bIsShuttingDown) + cleanup(); } void CCompositor::setRandomSplash() { @@ -432,8 +433,16 @@ void CCompositor::cleanEnvironment() { } } +void CCompositor::stopCompositor() { + Debug::log(LOG, "Hyprland is stopping!"); + + // this stops the wayland loop, wl_display_run + wl_display_terminate(m_sWLDisplay); + m_bIsShuttingDown = true; +} + void CCompositor::cleanup() { - if (!m_sWLDisplay || m_bIsShuttingDown) + if (!m_sWLDisplay) return; signal(SIGABRT, SIG_DFL); @@ -507,13 +516,8 @@ void CCompositor::cleanup() { if (m_critSigSource) wl_event_source_remove(m_critSigSource); - wl_event_loop_destroy(m_sWLEventLoop); - wl_display_terminate(m_sWLDisplay); - m_sWLDisplay = nullptr; - - std::string waylandSocket = std::string{getenv("XDG_RUNTIME_DIR")} + "/" + m_szWLDisplaySocket; - std::filesystem::remove(waylandSocket); - std::filesystem::remove(waylandSocket + ".lock"); + // this frees all wayland resources, including sockets + wl_display_destroy(m_sWLDisplay); } void CCompositor::initManagers(eManagersInitStage stage) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index a274ca58..da390b44 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -71,6 +71,7 @@ class CCompositor { void initServer(std::string socketName, int socketFd); void startCompositor(); + void stopCompositor(); void cleanup(); void createLockFile(); void removeLockFile(); diff --git a/src/main.cpp b/src/main.cpp index 3e51c6c8..e85b0a22 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -157,11 +157,9 @@ int main(int argc, char** argv) { // If all's good to go, start. g_pCompositor->startCompositor(); - g_pCompositor->m_bIsShuttingDown = true; + g_pCompositor->cleanup(); - // If we are here it means we got yote. - Debug::log(LOG, "Hyprland reached the end."); - g_pCompositor.reset(); + Debug::log(LOG, "Hyprland has reached the end."); return EXIT_SUCCESS; } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index fda27598..ed76575a 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1662,7 +1662,7 @@ void CKeybindManager::renameWorkspace(std::string args) { } void CKeybindManager::exitHyprland(std::string argz) { - g_pEventLoopManager->doLater([]() { g_pCompositor->cleanup(); }); + g_pCompositor->stopCompositor(); } void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 5a44680f..ef2260cc 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -166,3 +166,57 @@ CProtocolManager::CProtocolManager() { m_pGlobalShortcutsProtocolManager = std::make_unique(); m_pScreencopyProtocolManager = std::make_unique(); } + +CProtocolManager::~CProtocolManager() { + // this is dumb but i don't want to replace all 600 PROTO with the right thing + + // Output + PROTO::outputs.clear(); + + // Core + PROTO::seat.reset(); + PROTO::data.reset(); + PROTO::compositor.reset(); + PROTO::subcompositor.reset(); + PROTO::shm.reset(); + + // Extensions + PROTO::viewport.reset(); + PROTO::tearing.reset(); + PROTO::fractional.reset(); + PROTO::xdgOutput.reset(); + PROTO::cursorShape.reset(); + PROTO::idleInhibit.reset(); + PROTO::relativePointer.reset(); + PROTO::xdgDecoration.reset(); + PROTO::alphaModifier.reset(); + PROTO::gamma.reset(); + PROTO::foreignToplevel.reset(); + PROTO::pointerGestures.reset(); + PROTO::foreignToplevelWlr.reset(); + PROTO::shortcutsInhibit.reset(); + PROTO::textInputV3.reset(); + PROTO::constraints.reset(); + PROTO::outputPower.reset(); + PROTO::activation.reset(); + PROTO::idle.reset(); + PROTO::sessionLock.reset(); + PROTO::ime.reset(); + PROTO::virtualKeyboard.reset(); + PROTO::virtualPointer.reset(); + PROTO::outputManagement.reset(); + PROTO::serverDecorationKDE.reset(); + PROTO::focusGrab.reset(); + PROTO::tablet.reset(); + PROTO::layerShell.reset(); + PROTO::presentation.reset(); + PROTO::xdgShell.reset(); + PROTO::dataWlr.reset(); + PROTO::primarySelection.reset(); + PROTO::xwaylandShell.reset(); + + PROTO::lease.reset(); + PROTO::sync.reset(); + PROTO::mesaDRM.reset(); + PROTO::linuxDma.reset(); +} diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 91fb82a0..6a780bdc 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -12,6 +12,7 @@ class CProtocolManager { public: CProtocolManager(); + ~CProtocolManager(); // TODO: rewrite to use the new protocol framework std::unique_ptr m_pToplevelExportProtocolManager; diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index ed7a4f72..3131531a 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -19,8 +19,14 @@ CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEvent } CEventLoopManager::~CEventLoopManager() { + for (auto& eventSource : m_sWayland.aqEventSources) { + wl_event_source_remove(eventSource); + } + if (m_sWayland.eventSource) wl_event_source_remove(m_sWayland.eventSource); + if (m_sIdle.eventSource) + wl_event_source_remove(m_sIdle.eventSource); } static int timerWrite(int fd, uint32_t mask, void* data) { diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index b376cae3..898f0e07 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -8,13 +8,20 @@ static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint } static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->displayDestroy(); + CGlobalShortcutsProtocolManager* proto = wl_container_of(listener, proto, m_liDisplayDestroy); + proto->displayDestroy(); } void CGlobalShortcutsProtocolManager::displayDestroy() { + wl_list_remove(&m_liDisplayDestroy.link); + wl_list_init(&m_liDisplayDestroy.link); wl_global_destroy(m_pGlobal); } +CGlobalShortcutsProtocolManager::~CGlobalShortcutsProtocolManager() { + displayDestroy(); +} + CGlobalShortcutsProtocolManager::CGlobalShortcutsProtocolManager() { m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_global_shortcuts_manager_v1_interface, GLOBAL_SHORTCUTS_VERSION, this, bindManagerInt); @@ -148,4 +155,4 @@ void CGlobalShortcutsProtocolManager::destroyShortcut(wl_resource* resource) { for (auto& c : m_vClients) { std::erase_if(c->shortcuts, [&](const auto& other) { return other->resource == resource; }); } -} \ No newline at end of file +} diff --git a/src/protocols/GlobalShortcuts.hpp b/src/protocols/GlobalShortcuts.hpp index 07c484c6..5fd03465 100644 --- a/src/protocols/GlobalShortcuts.hpp +++ b/src/protocols/GlobalShortcuts.hpp @@ -17,6 +17,8 @@ struct SShortcutClient { class CGlobalShortcutsProtocolManager { public: CGlobalShortcutsProtocolManager(); + ~CGlobalShortcutsProtocolManager(); + void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); void displayDestroy(); @@ -29,11 +31,12 @@ class CGlobalShortcutsProtocolManager { std::vector getAllShortcuts(); + wl_listener m_liDisplayDestroy; + private: std::vector> m_vClients; SShortcutClient* clientFromWlClient(wl_client* client); wl_global* m_pGlobal = nullptr; - wl_listener m_liDisplayDestroy; -}; \ No newline at end of file +}; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 5d1c9332..98cb0be9 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -16,15 +16,22 @@ static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint } static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - g_pProtocolManager->m_pScreencopyProtocolManager->displayDestroy(); + CScreencopyProtocolManager* proto = wl_container_of(listener, proto, m_liDisplayDestroy); + proto->displayDestroy(); } void CScreencopyProtocolManager::displayDestroy() { + wl_list_remove(&m_liDisplayDestroy.link); + wl_list_init(&m_liDisplayDestroy.link); wl_global_destroy(m_pGlobal); } static SScreencopyFrame* frameFromResource(wl_resource*); +CScreencopyProtocolManager::~CScreencopyProtocolManager() { + displayDestroy(); +} + CScreencopyProtocolManager::CScreencopyProtocolManager() { m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &zwlr_screencopy_manager_v1_interface, SCREENCOPY_VERSION, this, bindManagerInt); diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index 4999773b..d564e432 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -70,17 +70,20 @@ struct SScreencopyFrame { class CScreencopyProtocolManager { public: CScreencopyProtocolManager(); + ~CScreencopyProtocolManager(); - void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); - void removeClient(CScreencopyClient* client, bool force = false); - void removeFrame(SScreencopyFrame* frame, bool force = false); - void displayDestroy(); + void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); + void removeClient(CScreencopyClient* client, bool force = false); + void removeFrame(SScreencopyFrame* frame, bool force = false); + void displayDestroy(); - void captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, CBox box = {0, 0, 0, 0}); + void captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, CBox box = {0, 0, 0, 0}); - void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer); + void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer); - void onOutputCommit(CMonitor* pMonitor); + void onOutputCommit(CMonitor* pMonitor); + + wl_listener m_liDisplayDestroy; private: wl_global* m_pGlobal = nullptr; @@ -90,8 +93,6 @@ class CScreencopyProtocolManager { SP m_pSoftwareCursorTimer; bool m_bTimerArmed = false; - wl_listener m_liDisplayDestroy; - std::vector m_vFramesAwaitingWrite; SP m_pLastMonitorBackBuffer; @@ -103,4 +104,4 @@ class CScreencopyProtocolManager { bool copyFrameShm(SScreencopyFrame* frame, timespec* now); friend class CScreencopyClient; -}; \ No newline at end of file +}; diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index 7c16ef8c..12068671 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -10,13 +10,20 @@ static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint } static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->displayDestroy(); + CTextInputV1ProtocolManager* proto = wl_container_of(listener, proto, m_liDisplayDestroy); + proto->displayDestroy(); } void CTextInputV1ProtocolManager::displayDestroy() { + wl_list_remove(&m_liDisplayDestroy.link); + wl_list_init(&m_liDisplayDestroy.link); wl_global_destroy(m_pGlobal); } +CTextInputV1ProtocolManager::~CTextInputV1ProtocolManager() { + displayDestroy(); +} + CTextInputV1ProtocolManager::CTextInputV1ProtocolManager() { m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &zwp_text_input_manager_v1_interface, TEXT_INPUT_VERSION, this, bindManagerInt); @@ -220,4 +227,4 @@ void CTextInputV1ProtocolManager::handleCommitState(wl_client* client, wl_resour void CTextInputV1ProtocolManager::handleInvokeAction(wl_client* client, wl_resource* resource, uint32_t button, uint32_t index) { ; -} \ No newline at end of file +} diff --git a/src/protocols/TextInputV1.hpp b/src/protocols/TextInputV1.hpp index 0a1203f0..e56a8990 100644 --- a/src/protocols/TextInputV1.hpp +++ b/src/protocols/TextInputV1.hpp @@ -47,6 +47,7 @@ struct STextInputV1 { class CTextInputV1ProtocolManager { public: CTextInputV1ProtocolManager(); + ~CTextInputV1ProtocolManager(); void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); void createTI(wl_client* client, wl_resource* resource, uint32_t id); @@ -55,21 +56,22 @@ class CTextInputV1ProtocolManager { void displayDestroy(); // handlers for tiv1 - void handleActivate(wl_client* client, wl_resource* resource, wl_resource* seat, wl_resource* surface); - void handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat); - void handleShowInputPanel(wl_client* client, wl_resource* resource); - void handleHideInputPanel(wl_client* client, wl_resource* resource); - void handleReset(wl_client* client, wl_resource* resource); - void handleSetSurroundingText(wl_client* client, wl_resource* resource, const char* text, uint32_t cursor, uint32_t anchor); - void handleSetContentType(wl_client* client, wl_resource* resource, uint32_t hint, uint32_t purpose); - void handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height); - void handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language); - void handleCommitState(wl_client* client, wl_resource* resource, uint32_t serial); - void handleInvokeAction(wl_client* client, wl_resource* resource, uint32_t button, uint32_t index); + void handleActivate(wl_client* client, wl_resource* resource, wl_resource* seat, wl_resource* surface); + void handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat); + void handleShowInputPanel(wl_client* client, wl_resource* resource); + void handleHideInputPanel(wl_client* client, wl_resource* resource); + void handleReset(wl_client* client, wl_resource* resource); + void handleSetSurroundingText(wl_client* client, wl_resource* resource, const char* text, uint32_t cursor, uint32_t anchor); + void handleSetContentType(wl_client* client, wl_resource* resource, uint32_t hint, uint32_t purpose); + void handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height); + void handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language); + void handleCommitState(wl_client* client, wl_resource* resource, uint32_t serial); + void handleInvokeAction(wl_client* client, wl_resource* resource, uint32_t button, uint32_t index); + + wl_listener m_liDisplayDestroy; private: wl_global* m_pGlobal = nullptr; - wl_listener m_liDisplayDestroy; std::vector> m_pClients; -}; \ No newline at end of file +}; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index e982ad6f..28f49c6a 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -15,13 +15,20 @@ static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint } static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - g_pProtocolManager->m_pToplevelExportProtocolManager->displayDestroy(); + CToplevelExportProtocolManager* proto = wl_container_of(listener, proto, m_liDisplayDestroy); + proto->displayDestroy(); } void CToplevelExportProtocolManager::displayDestroy() { + wl_list_remove(&m_liDisplayDestroy.link); + wl_list_init(&m_liDisplayDestroy.link); wl_global_destroy(m_pGlobal); } +CToplevelExportProtocolManager::~CToplevelExportProtocolManager() { + displayDestroy(); +} + CToplevelExportProtocolManager::CToplevelExportProtocolManager() { #ifndef GLES32 diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index c3620d41..71a6df18 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -13,23 +13,24 @@ class CWindow; class CToplevelExportProtocolManager { public: CToplevelExportProtocolManager(); + ~CToplevelExportProtocolManager(); - void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); - void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, PHLWINDOW handle); - void removeClient(CScreencopyClient* client, bool force = false); - void removeFrame(SScreencopyFrame* frame, bool force = false); - void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage); - void displayDestroy(); - void onWindowUnmap(PHLWINDOW pWindow); - void onOutputCommit(CMonitor* pMonitor); + void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); + void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, PHLWINDOW handle); + void removeClient(CScreencopyClient* client, bool force = false); + void removeFrame(SScreencopyFrame* frame, bool force = false); + void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage); + void displayDestroy(); + void onWindowUnmap(PHLWINDOW pWindow); + void onOutputCommit(CMonitor* pMonitor); + + wl_listener m_liDisplayDestroy; private: wl_global* m_pGlobal = nullptr; std::list m_lFrames; std::list m_lClients; - wl_listener m_liDisplayDestroy; - std::vector m_vFramesAwaitingWrite; void shareFrame(SScreencopyFrame* frame); @@ -38,4 +39,4 @@ class CToplevelExportProtocolManager { void sendDamage(SScreencopyFrame* frame); friend class CScreencopyClient; -}; \ No newline at end of file +}; diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 23a6721c..71c43300 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -6,7 +6,8 @@ static void bindManagerInternal(wl_client* client, void* data, uint32_t ver, uin } static void displayDestroyInternal(struct wl_listener* listener, void* data) { - ((IWaylandProtocol*)data)->onDisplayDestroy(); + IWaylandProtocol* proto = wl_container_of(listener, proto, m_liDisplayDestroy); + proto->onDisplayDestroy(); } void IWaylandProtocol::onDisplayDestroy() { diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index b443e253..6154fa30 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -26,8 +26,9 @@ class IWaylandProtocol { Debug::log(level, std::format("[{}] ", m_szName) + std::vformat(fmt.get(), std::make_format_args(args...))); }; + wl_listener m_liDisplayDestroy; + private: std::string m_szName; wl_global* m_pGlobal = nullptr; - wl_listener m_liDisplayDestroy; -}; \ No newline at end of file +};