From 68456a5d9a54f34b70a8261153dc7d35c17f2bf0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 19 Feb 2026 00:49:43 +0000 Subject: [PATCH] desktop/window: add stable id and use it for foreign --- src/debug/HyprCtl.cpp | 10 ++++++---- src/desktop/view/Window.cpp | 8 ++++++-- src/desktop/view/Window.hpp | 3 +++ src/protocols/ForeignToplevel.cpp | 18 +++++++++--------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 0c33c7a4..ecd56815 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -394,7 +394,8 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "inhibitingIdle": {}, "xdgTag": "{}", "xdgDescription": "{}", - "contentType": "{}" + "contentType": "{}", + "stable_id": "{:x}" }},)#", rc(w.get()), (w->m_isMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), sc(w->m_realPosition->goal().x), sc(w->m_realPosition->goal().y), sc(w->m_realSize->goal().x), sc(w->m_realSize->goal().y), w->m_workspace ? w->workspaceID() : WORKSPACE_INVALID, @@ -403,7 +404,7 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { (sc(w->m_isX11) == 1 ? "true" : "false"), (w->m_pinned ? "true" : "false"), sc(w->m_fullscreenState.internal), sc(w->m_fullscreenState.client), (w->m_createdOverFullscreen ? "true" : "false"), getGroupedData(w, format), getTagsData(w, format), rc(w->m_swallowed.get()), getFocusHistoryID(w), (g_pInputManager->isWindowInhibiting(w, false) ? "true" : "false"), escapeJSONStrings(w->xdgTag().value_or("")), escapeJSONStrings(w->xdgDescription().value_or("")), - escapeJSONStrings(NContentType::toString(w->getContentType()))); + escapeJSONStrings(NContentType::toString(w->getContentType())), w->m_stableID); } else { return std::format( "Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tpseudo: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " @@ -411,13 +412,14 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "{}\n\txwayland: {}\n\tpinned: " "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\toverFullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: " "{}\n\txdgTag: " - "{}\n\txdgDescription: {}\n\tcontentType: {}\n\n", + "{}\n\txdgDescription: {}\n\tcontentType: {}\n\tstableID: {:x}\n\n", rc(w.get()), w->m_title, sc(w->m_isMapped), sc(w->isHidden()), sc(w->m_realPosition->goal().x), sc(w->m_realPosition->goal().y), sc(w->m_realSize->goal().x), sc(w->m_realSize->goal().y), w->m_workspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_workspace ? "" : w->m_workspace->m_name), sc(w->m_isFloating), sc(w->m_isPseudotiled), w->monitorID(), w->m_class, w->m_title, w->m_initialClass, w->m_initialTitle, w->getPID(), sc(w->m_isX11), sc(w->m_pinned), sc(w->m_fullscreenState.internal), sc(w->m_fullscreenState.client), sc(w->m_createdOverFullscreen), getGroupedData(w, format), getTagsData(w, format), rc(w->m_swallowed.get()), getFocusHistoryID(w), - sc(g_pInputManager->isWindowInhibiting(w, false)), w->xdgTag().value_or(""), w->xdgDescription().value_or(""), NContentType::toString(w->getContentType())); + sc(g_pInputManager->isWindowInhibiting(w, false)), w->xdgTag().value_or(""), w->xdgDescription().value_or(""), NContentType::toString(w->getContentType()), + w->m_stableID); } } diff --git a/src/desktop/view/Window.cpp b/src/desktop/view/Window.cpp index 30fb131d..7e1131b1 100644 --- a/src/desktop/view/Window.cpp +++ b/src/desktop/view/Window.cpp @@ -53,6 +53,10 @@ using enum NContentType::eContentType; using namespace Desktop; using namespace Desktop::View; +// I wish I had an elven wife instead of a windowIDCounter +static uint64_t windowIDCounter = 0x18000000; + +// PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); @@ -105,7 +109,7 @@ PHLWINDOW CWindow::create(SP resource) { return pWindow; } -CWindow::CWindow(SP resource) : IView(CWLSurface::create()), m_xdgSurface(resource) { +CWindow::CWindow(SP resource) : IView(CWLSurface::create()), m_xdgSurface(resource), m_stableID(windowIDCounter++) { m_listeners.map = m_xdgSurface->m_events.map.listen([this] { mapWindow(); }); m_listeners.ack = m_xdgSurface->m_events.ack.listen([this](uint32_t d) { onAck(d); }); m_listeners.unmap = m_xdgSurface->m_events.unmap.listen([this] { unmapWindow(); }); @@ -115,7 +119,7 @@ CWindow::CWindow(SP resource) : IView(CWLSurface::create()) m_listeners.updateMetadata = m_xdgSurface->m_toplevel->m_events.metadataChanged.listen([this] { onUpdateMeta(); }); } -CWindow::CWindow(SP surface) : IView(CWLSurface::create()), m_xwaylandSurface(surface) { +CWindow::CWindow(SP surface) : IView(CWLSurface::create()), m_xwaylandSurface(surface), m_stableID(windowIDCounter++) { m_listeners.map = m_xwaylandSurface->m_events.map.listen([this] { mapWindow(); }); m_listeners.unmap = m_xwaylandSurface->m_events.unmap.listen([this] { unmapWindow(); }); m_listeners.destroy = m_xwaylandSurface->m_events.destroy.listen([this] { destroyWindow(); }); diff --git a/src/desktop/view/Window.hpp b/src/desktop/view/Window.hpp index 294da721..38e8ef0b 100644 --- a/src/desktop/view/Window.hpp +++ b/src/desktop/view/Window.hpp @@ -239,6 +239,9 @@ namespace Desktop::View { bool m_tearingHint = false; + // Stable ID for ext_foreign_toplevel_list + const uint64_t m_stableID = 0x2137; + // ANR PHLANIMVAR m_notRespondingTint; diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 5515d2fb..93506410 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -54,26 +54,26 @@ void CForeignToplevelList::onMap(PHLWINDOW pWindow) { std::erase_if(m_handles, [&](const auto& other) { return other.get() == OLDHANDLE.get(); }); } - const auto NEWHANDLE = PROTO::foreignToplevel->m_handles.emplace_back( + auto newHandle = PROTO::foreignToplevel->m_handles.emplace_back( makeShared(makeShared(m_resource->client(), m_resource->version(), 0), pWindow)); - if (!NEWHANDLE->good()) { + if (!newHandle->good()) { LOGM(Log::ERR, "Couldn't create a foreign handle"); m_resource->noMemory(); PROTO::foreignToplevel->m_handles.pop_back(); return; } - const auto IDENTIFIER = std::format("{:08x}->{:016x}", sc(rc(this) & 0xFFFFFFFF), rc(pWindow.get())); + const auto IDENTIFIER = std::format("{:x}", pWindow->m_stableID); LOGM(Log::DEBUG, "Newly mapped window gets an identifier of {}", IDENTIFIER); - m_resource->sendToplevel(NEWHANDLE->m_resource.get()); - NEWHANDLE->m_resource->sendIdentifier(IDENTIFIER.c_str()); - NEWHANDLE->m_resource->sendAppId(pWindow->m_initialClass.c_str()); - NEWHANDLE->m_resource->sendTitle(pWindow->m_initialTitle.c_str()); - NEWHANDLE->m_resource->sendDone(); + m_resource->sendToplevel(newHandle->m_resource.get()); + newHandle->m_resource->sendIdentifier(IDENTIFIER.c_str()); + newHandle->m_resource->sendAppId(pWindow->m_initialClass.c_str()); + newHandle->m_resource->sendTitle(pWindow->m_initialTitle.c_str()); + newHandle->m_resource->sendDone(); - m_handles.push_back(NEWHANDLE); + m_handles.emplace_back(std::move(newHandle)); } SP CForeignToplevelList::handleForWindow(PHLWINDOW pWindow) {