diff --git a/CMakeLists.txt b/CMakeLists.txt index 8926f35c..d11ec813 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -252,7 +252,6 @@ target_link_libraries(Hyprland protocol("protocols/idle.xml" "idle" true) protocol("protocols/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" true) protocol("protocols/tablet-unstable-v2.xml" "tablet-unstable-v2" true) -protocol("protocols/wlr-foreign-toplevel-management-unstable-v1.xml" "wlr-foreign-toplevel-management-unstable-v1" true) protocol("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true) protocol("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true) protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) @@ -263,6 +262,7 @@ protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unst protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) protocolNew("protocols/wlr-gamma-control-unstable-v1.xml" "wlr-gamma-control-unstable-v1" true) +protocolNew("protocols/wlr-foreign-toplevel-management-unstable-v1.xml" "wlr-foreign-toplevel-management-unstable-v1" true) protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false) protocolNew("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false) diff --git a/protocols/meson.build b/protocols/meson.build index 9170f7f2..0006f401 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -27,7 +27,6 @@ protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], - ['wlr-foreign-toplevel-management-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], ['wlr-output-power-management-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'], @@ -40,6 +39,7 @@ protocols = [ new_protocols = [ ['wlr-gamma-control-unstable-v1.xml'], + ['wlr-foreign-toplevel-management-unstable-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], diff --git a/src/Compositor.cpp b/src/Compositor.cpp index de8e1f94..37b0e400 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -219,8 +219,6 @@ void CCompositor::initServer() { m_sWLRVirtPtrMgr = wlr_virtual_pointer_manager_v1_create(m_sWLDisplay); - m_sWLRToplevelMgr = wlr_foreign_toplevel_manager_v1_create(m_sWLDisplay); - m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend); if (!m_sWRLDRMLeaseMgr) { Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager"); @@ -954,9 +952,6 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { updateWindowAnimatedDecorationValues(PLASTWINDOW); g_pXWaylandManager->activateWindow(PLASTWINDOW, false); - - if (PLASTWINDOW->m_phForeignToplevel) - wlr_foreign_toplevel_handle_v1_set_activated(PLASTWINDOW->m_phForeignToplevel, false); } wlr_seat_keyboard_notify_clear_focus(m_sSeat.seat); @@ -1016,9 +1011,6 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { if (!pWindow->m_bIsX11 || pWindow->m_iX11Type == 1) g_pXWaylandManager->activateWindow(PLASTWINDOW, false); - - if (PLASTWINDOW->m_phForeignToplevel) - wlr_foreign_toplevel_handle_v1_set_activated(PLASTWINDOW->m_phForeignToplevel, false); } m_pLastWindow = PLASTWINDOW; @@ -1044,17 +1036,6 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) { g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(pWindow); - // TODO: implement this better - if (!PLASTWINDOW && pWindow->m_sGroupData.pNextWindow) { - for (auto curr = pWindow->m_sGroupData.pNextWindow; curr != pWindow; curr = curr->m_sGroupData.pNextWindow) { - if (curr->m_phForeignToplevel) - wlr_foreign_toplevel_handle_v1_set_activated(curr->m_phForeignToplevel, false); - } - } - - if (pWindow->m_phForeignToplevel) - wlr_foreign_toplevel_handle_v1_set_activated(pWindow->m_phForeignToplevel, true); - g_pInputManager->recheckIdleInhibitorStatus(); // move to front of the window history @@ -1203,23 +1184,6 @@ CWindow* CCompositor::getWindowFromHandle(uint32_t handle) { return nullptr; } -CWindow* CCompositor::getWindowFromZWLRHandle(wl_resource* handle) { - for (auto& w : m_vWindows) { - if (!w->m_bIsMapped || w->isHidden() || !w->m_phForeignToplevel) - continue; - - wl_resource* current; - - wl_list_for_each(current, &w->m_phForeignToplevel->resources, link) { - if (current == handle) { - return w.get(); - } - } - } - - return nullptr; -} - CWindow* CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { for (auto& w : m_vWindows) { if (w->workspaceID() == ID && w->m_bIsFullscreen) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index c5ac7222..7d1b3b35 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -66,7 +66,6 @@ class CCompositor { wlr_pointer_constraints_v1* m_sWLRPointerConstraints; wlr_server_decoration_manager* m_sWLRServerDecoMgr; wlr_virtual_pointer_manager_v1* m_sWLRVirtPtrMgr; - wlr_foreign_toplevel_manager_v1* m_sWLRToplevelMgr; wlr_tablet_manager_v2* m_sWLRTabletManager; wlr_xdg_foreign_registry* m_sWLRForeignRegistry; wlr_output_power_manager_v1* m_sWLROutputPowerMgr; @@ -136,7 +135,6 @@ class CCompositor { CMonitor* getRealMonitorFromOutput(wlr_output*); CWindow* getWindowFromSurface(wlr_surface*); CWindow* getWindowFromHandle(uint32_t); - CWindow* getWindowFromZWLRHandle(wl_resource*); bool isWorkspaceVisible(PHLWORKSPACE); PHLWORKSPACE getWorkspaceByID(const int&); PHLWORKSPACE getWorkspaceByName(const std::string&); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index cebdad49..b469102f 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -274,66 +274,8 @@ IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) { return nullptr; } -void CWindow::createToplevelHandle() { - if (m_bIsX11 && (m_bX11DoesntWantBorders || m_iX11Type == 2)) - return; // don't create a toplevel - - m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create(g_pCompositor->m_sWLRToplevelMgr); - - wlr_foreign_toplevel_handle_v1_set_app_id(m_phForeignToplevel, g_pXWaylandManager->getAppIDClass(this).c_str()); - wlr_foreign_toplevel_handle_v1_output_enter(m_phForeignToplevel, g_pCompositor->getMonitorFromID(m_iMonitorID)->output); - wlr_foreign_toplevel_handle_v1_set_title(m_phForeignToplevel, m_szTitle.c_str()); - wlr_foreign_toplevel_handle_v1_set_maximized(m_phForeignToplevel, false); - wlr_foreign_toplevel_handle_v1_set_minimized(m_phForeignToplevel, false); - wlr_foreign_toplevel_handle_v1_set_fullscreen(m_phForeignToplevel, false); - - // handle events - hyprListener_toplevelActivate.initCallback( - &m_phForeignToplevel->events.request_activate, [&](void* owner, void* data) { g_pLayoutManager->getCurrentLayout()->requestFocusForWindow(this); }, this, "Toplevel"); - - hyprListener_toplevelFullscreen.initCallback( - &m_phForeignToplevel->events.request_fullscreen, - [&](void* owner, void* data) { - const auto EV = (wlr_foreign_toplevel_handle_v1_fullscreen_event*)data; - - g_pCompositor->setWindowFullscreen(this, EV->fullscreen, FULLSCREEN_FULL); - }, - this, "Toplevel"); - - hyprListener_toplevelClose.initCallback( - &m_phForeignToplevel->events.request_close, [&](void* owner, void* data) { g_pCompositor->closeWindow(this); }, this, "Toplevel"); - - m_iLastToplevelMonitorID = m_iMonitorID; -} - -void CWindow::destroyToplevelHandle() { - if (!m_phForeignToplevel) - return; - - hyprListener_toplevelActivate.removeCallback(); - hyprListener_toplevelClose.removeCallback(); - hyprListener_toplevelFullscreen.removeCallback(); - - wlr_foreign_toplevel_handle_v1_destroy(m_phForeignToplevel); - m_phForeignToplevel = nullptr; -} - void CWindow::updateToplevel() { updateSurfaceScaleTransformDetails(); - - if (!m_phForeignToplevel) - return; - - wlr_foreign_toplevel_handle_v1_set_title(m_phForeignToplevel, m_szTitle.c_str()); - wlr_foreign_toplevel_handle_v1_set_fullscreen(m_phForeignToplevel, m_bIsFullscreen); - - if (m_iLastToplevelMonitorID != m_iMonitorID) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iLastToplevelMonitorID); PMONITOR && PMONITOR->m_bEnabled) - wlr_foreign_toplevel_handle_v1_output_leave(m_phForeignToplevel, PMONITOR->output); - wlr_foreign_toplevel_handle_v1_output_enter(m_phForeignToplevel, g_pCompositor->getMonitorFromID(m_iMonitorID)->output); - - m_iLastToplevelMonitorID = m_iMonitorID; - } } void sendEnterIter(wlr_surface* pSurface, int x, int y, void* data) { @@ -1311,3 +1253,21 @@ std::unordered_map CWindow::getEnv() { return results; } + +void CWindow::activate() { + static auto PFOCUSONACTIVATE = CConfigValue("misc:focus_on_activate"); + + g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)this)}); + EMIT_HOOK_EVENT("urgent", this); + + m_bIsUrgent = true; + + if (!*PFOCUSONACTIVATE || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY)) + return; + + if (m_bIsFloating) + g_pCompositor->changeWindowZOrder(this, true); + + g_pCompositor->focusWindow(this); + g_pCompositor->warpCursorTo(middle()); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 4084bf57..b101700a 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -328,9 +328,6 @@ class CWindow { // for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window. CWindow* m_pLastCycledWindow = nullptr; - // Foreign Toplevel proto - wlr_foreign_toplevel_handle_v1* m_phForeignToplevel = nullptr; - // Window decorations std::deque> m_dWindowDecorations; std::vector m_vDecosToRemove; @@ -398,8 +395,6 @@ class CWindow { pid_t getPID(); IHyprWindowDecoration* getDecorationByType(eDecorationType); void removeDecorationByType(eDecorationType); - void createToplevelHandle(); - void destroyToplevelHandle(); void updateToplevel(); void updateSurfaceScaleTransformDetails(); void moveToWorkspace(PHLWORKSPACE); @@ -420,6 +415,7 @@ class CWindow { bool visibleOnMonitor(CMonitor* pMonitor); int workspaceID(); bool onSpecialWorkspace(); + void activate(); int getRealBorderSize(); void updateSpecialRenderData(); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index e2483379..6455c530 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -110,9 +110,6 @@ void Events::listener_mapWindow(void* owner, void* data) { // Set all windows tiled regardless of anything g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM); - // Foreign Toplevel - PWINDOW->createToplevelHandle(); - // checks if the window wants borders and sets the appropriate flag g_pXWaylandManager->checkBorders(PWINDOW); @@ -786,9 +783,6 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true); PWINDOW->m_fAlpha = 0.f; - // Destroy Foreign Toplevel - PWINDOW->destroyToplevelHandle(); - // recheck idle inhibitors g_pInputManager->recheckIdleInhibitorStatus(); @@ -1013,9 +1007,7 @@ void Events::listener_fullscreenWindow(void* owner, void* data) { } void Events::listener_activateXDG(wl_listener* listener, void* data) { - const auto E = (wlr_xdg_activation_v1_request_activate_event*)data; - - static auto PFOCUSONACTIVATE = CConfigValue("misc:focus_on_activate"); + const auto E = (wlr_xdg_activation_v1_request_activate_event*)data; Debug::log(LOG, "Activate request for surface at {:x}", (uintptr_t)E->surface); @@ -1027,25 +1019,11 @@ void Events::listener_activateXDG(wl_listener* listener, void* data) { if (!PWINDOW || PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE)) return; - g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)}); - EMIT_HOOK_EVENT("urgent", PWINDOW); - - PWINDOW->m_bIsUrgent = true; - - if (!*PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY)) - return; - - if (PWINDOW->m_bIsFloating) - g_pCompositor->changeWindowZOrder(PWINDOW, true); - - g_pCompositor->focusWindow(PWINDOW); - g_pCompositor->warpCursorTo(PWINDOW->middle()); + PWINDOW->activate(); } void Events::listener_activateX11(void* owner, void* data) { - const auto PWINDOW = (CWindow*)owner; - - static auto PFOCUSONACTIVATE = CConfigValue("misc:focus_on_activate"); + const auto PWINDOW = (CWindow*)owner; Debug::log(LOG, "X11 Activate request for window {}", PWINDOW); @@ -1066,17 +1044,7 @@ void Events::listener_activateX11(void* owner, void* data) { if (PWINDOW == g_pCompositor->m_pLastWindow || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE)) return; - g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)PWINDOW)}); - EMIT_HOOK_EVENT("urgent", PWINDOW); - - if (!*PFOCUSONACTIVATE || (PWINDOW->m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY)) - return; - - if (PWINDOW->m_bIsFloating) - g_pCompositor->changeWindowZOrder(PWINDOW, true); - - g_pCompositor->focusWindow(PWINDOW); - g_pCompositor->warpCursorTo(PWINDOW->middle()); + PWINDOW->activate(); } void Events::listener_configureX11(void* owner, void* data) { @@ -1275,9 +1243,8 @@ void Events::listener_requestMaximize(void* owner, void* data) { Debug::log(LOG, "Maximize request for {}", PWINDOW); if (!PWINDOW->m_bIsX11) { - const auto EV = (wlr_foreign_toplevel_handle_v1_maximized_event*)data; - g_pCompositor->setWindowFullscreen(PWINDOW, EV ? EV->maximized : !PWINDOW->m_bIsFullscreen, + g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED); // this will be rejected if there already is a fullscreen window wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg); @@ -1305,9 +1272,8 @@ void Events::listener_requestMinimize(void* owner, void* data) { wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow != PWINDOW); // fucking DXVK } else { - const auto E = (wlr_foreign_toplevel_handle_v1_minimized_event*)data; - g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW, E ? (int)E->minimized : 1)}); - EMIT_HOOK_EVENT("minimize", (std::vector{PWINDOW, (void*)(E ? (uint64_t)E->minimized : 1)})); + g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW, 1)}); + EMIT_HOOK_EVENT("minimize", (std::vector{PWINDOW, (void*)(1)})); } } diff --git a/src/includes.hpp b/src/includes.hpp index 26dd0c49..e78a1880 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -70,7 +70,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 3552fd9c..8605e8bd 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -11,6 +11,7 @@ #include "../protocols/GammaControl.hpp" #include "../protocols/ForeignToplevel.hpp" #include "../protocols/PointerGestures.hpp" +#include "../protocols/ForeignToplevelWlr.hpp" #include "tearing-control-v1.hpp" #include "fractional-scale-v1.hpp" @@ -23,20 +24,22 @@ #include "wlr-gamma-control-unstable-v1.hpp" #include "ext-foreign-toplevel-list-v1.hpp" #include "pointer-gestures-unstable-v1.hpp" +#include "wlr-foreign-toplevel-management-unstable-v1.hpp" CProtocolManager::CProtocolManager() { - PROTO::tearing = std::make_unique(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); - PROTO::fractional = std::make_unique(&wp_fractional_scale_manager_v1_interface, 1, "FractionalScale"); - PROTO::xdgOutput = std::make_unique(&zxdg_output_manager_v1_interface, 3, "XDGOutput"); - PROTO::cursorShape = std::make_unique(&wp_cursor_shape_manager_v1_interface, 1, "CursorShape"); - PROTO::idleInhibit = std::make_unique(&zwp_idle_inhibit_manager_v1_interface, 1, "IdleInhibit"); - PROTO::relativePointer = std::make_unique(&zwp_relative_pointer_manager_v1_interface, 1, "RelativePointer"); - PROTO::xdgDecoration = std::make_unique(&zxdg_decoration_manager_v1_interface, 1, "XDGDecoration"); - PROTO::alphaModifier = std::make_unique(&wp_alpha_modifier_v1_interface, 1, "AlphaModifier"); - PROTO::gamma = std::make_unique(&zwlr_gamma_control_manager_v1_interface, 1, "GammaControl"); - PROTO::foreignToplevel = std::make_unique(&ext_foreign_toplevel_list_v1_interface, 1, "ForeignToplevel"); - PROTO::pointerGestures = std::make_unique(&zwp_pointer_gestures_v1_interface, 3, "PointerGestures"); + PROTO::tearing = std::make_unique(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); + PROTO::fractional = std::make_unique(&wp_fractional_scale_manager_v1_interface, 1, "FractionalScale"); + PROTO::xdgOutput = std::make_unique(&zxdg_output_manager_v1_interface, 3, "XDGOutput"); + PROTO::cursorShape = std::make_unique(&wp_cursor_shape_manager_v1_interface, 1, "CursorShape"); + PROTO::idleInhibit = std::make_unique(&zwp_idle_inhibit_manager_v1_interface, 1, "IdleInhibit"); + PROTO::relativePointer = std::make_unique(&zwp_relative_pointer_manager_v1_interface, 1, "RelativePointer"); + PROTO::xdgDecoration = std::make_unique(&zxdg_decoration_manager_v1_interface, 1, "XDGDecoration"); + PROTO::alphaModifier = std::make_unique(&wp_alpha_modifier_v1_interface, 1, "AlphaModifier"); + PROTO::gamma = std::make_unique(&zwlr_gamma_control_manager_v1_interface, 1, "GammaControl"); + PROTO::foreignToplevel = std::make_unique(&ext_foreign_toplevel_list_v1_interface, 1, "ForeignToplevel"); + PROTO::pointerGestures = std::make_unique(&zwp_pointer_gestures_v1_interface, 3, "PointerGestures"); + PROTO::foreignToplevelWlr = std::make_unique(&zwlr_foreign_toplevel_manager_v1_interface, 3, "ForeignToplevelWlr"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index cc7a8cac..c589c981 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -295,9 +295,6 @@ void CHyprXWaylandManager::setWindowFullscreen(CWindow* pWindow, bool fullscreen wlr_xwayland_surface_set_fullscreen(pWindow->m_uSurface.xwayland, fullscreen); else wlr_xdg_toplevel_set_fullscreen(pWindow->m_uSurface.xdg->toplevel, fullscreen); - - if (pWindow->m_phForeignToplevel) - wlr_foreign_toplevel_handle_v1_set_fullscreen(pWindow->m_phForeignToplevel, fullscreen); } Vector2D CHyprXWaylandManager::getMaxSizeForWindow(CWindow* pWindow) { diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index c502029c..5aaede1a 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -62,6 +62,8 @@ void CForeignToplevelList::onMap(CWindow* pWindow) { NEWHANDLE->resource->sendAppId(pWindow->m_szInitialClass.c_str()); NEWHANDLE->resource->sendTitle(pWindow->m_szInitialTitle.c_str()); NEWHANDLE->resource->sendDone(); + + handles.push_back(NEWHANDLE); } SP CForeignToplevelList::handleForWindow(CWindow* pWindow) { diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp new file mode 100644 index 00000000..436bf1d2 --- /dev/null +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -0,0 +1,354 @@ +#include "ForeignToplevelWlr.hpp" +#include +#include "../Compositor.hpp" + +#define LOGM PROTO::foreignToplevelWlr->protoLog + +CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP resource_, CWindow* pWindow_) : resource(resource_), pWindow(pWindow_) { + if (!resource_->resource()) + return; + + resource->setOnDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); }); + resource->setDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); }); + + resource->setActivate([this](CZwlrForeignToplevelHandleV1* p, wl_resource* seat) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_ACTIVATE) + return; + + pWindow->activate(); + }); + + resource->setSetFullscreen([this](CZwlrForeignToplevelHandleV1* p, wl_resource* output) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) + return; + + if (!pWindow->m_bIsMapped) { + pWindow->m_bWantsInitialFullscreen = true; + return; + } + + g_pCompositor->setWindowFullscreen(pWindow, true); + }); + + resource->setUnsetFullscreen([this](CZwlrForeignToplevelHandleV1* p) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) + return; + + g_pCompositor->setWindowFullscreen(pWindow, false); + }); + + resource->setSetMaximized([this](CZwlrForeignToplevelHandleV1* p) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) + return; + + if (!pWindow->m_bIsMapped) { + pWindow->m_bWantsInitialFullscreen = true; + return; + } + + g_pCompositor->setWindowFullscreen(pWindow, true, FULLSCREEN_MAXIMIZED); + }); + + resource->setUnsetMaximized([this](CZwlrForeignToplevelHandleV1* p) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) + return; + + g_pCompositor->setWindowFullscreen(pWindow, false); + }); + + resource->setClose([this](CZwlrForeignToplevelHandleV1* p) { + if (!pWindow) + return; + + g_pCompositor->closeWindow(pWindow); + }); +} + +bool CForeignToplevelHandleWlr::good() { + return resource->resource(); +} + +CWindow* CForeignToplevelHandleWlr::window() { + return pWindow; +} + +wl_resource* CForeignToplevelHandleWlr::res() { + return resource->resource(); +} + +void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { + if (lastMonitorID == (int64_t)pMonitor->ID) + return; + + const auto CLIENT = wl_resource_get_client(resource->resource()); + + struct wl_resource* outputResource; + + if (const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(lastMonitorID); PLASTMONITOR) { + wl_resource_for_each(outputResource, &PLASTMONITOR->output->resources) { + if (wl_resource_get_client(outputResource) != CLIENT) + continue; + + resource->sendOutputLeave(outputResource); + } + } + + wl_resource_for_each(outputResource, &pMonitor->output->resources) { + if (wl_resource_get_client(outputResource) != CLIENT) + continue; + + resource->sendOutputEnter(outputResource); + } + + lastMonitorID = pMonitor->ID; +} + +void CForeignToplevelHandleWlr::sendState() { + if (!pWindow || !pWindow->m_pWorkspace || !pWindow->m_bIsMapped) + return; + + wl_array state; + wl_array_init(&state); + + if (pWindow == g_pCompositor->m_pLastWindow) { + auto p = (uint32_t*)wl_array_add(&state, sizeof(uint32_t)); + *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED; + } + + if (pWindow->m_bIsFullscreen) { + auto p = (uint32_t*)wl_array_add(&state, sizeof(uint32_t)); + if (pWindow->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) + *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN; + else + *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED; + } + + resource->sendState(&state); + + wl_array_release(&state); +} + +CForeignToplevelWlrManager::CForeignToplevelWlrManager(SP resource_) : resource(resource_) { + if (!resource_->resource()) + return; + + resource->setOnDestroy([this](CZwlrForeignToplevelManagerV1* h) { PROTO::foreignToplevelWlr->onManagerResourceDestroy(this); }); + + resource->setStop([this](CZwlrForeignToplevelManagerV1* h) { + resource->sendFinished(); + finished = true; + LOGM(LOG, "CForeignToplevelWlrManager: finished"); + PROTO::foreignToplevelWlr->onManagerResourceDestroy(this); + }); + + for (auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_bFadingOut) + continue; + + onMap(w.get()); + } + + lastFocus = g_pCompositor->m_pLastWindow; +} + +void CForeignToplevelWlrManager::onMap(CWindow* pWindow) { + if (finished) + return; + + const auto NEWHANDLE = PROTO::foreignToplevelWlr->m_vHandles.emplace_back(std::make_shared( + std::make_shared(wl_resource_get_client(resource->resource()), wl_resource_get_version(resource->resource()), 0), pWindow)); + + if (!NEWHANDLE->good()) { + LOGM(ERR, "Couldn't create a foreign handle"); + wl_resource_post_no_memory(resource->resource()); + PROTO::foreignToplevelWlr->m_vHandles.pop_back(); + return; + } + + LOGM(LOG, "Newly mapped window {:016x}", (uintptr_t)pWindow); + resource->sendToplevel(NEWHANDLE->resource.get()); + NEWHANDLE->resource->sendAppId(pWindow->m_szInitialClass.c_str()); + NEWHANDLE->resource->sendTitle(pWindow->m_szInitialTitle.c_str()); + if (const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); PMONITOR) + NEWHANDLE->sendMonitor(PMONITOR); + NEWHANDLE->sendState(); + NEWHANDLE->resource->sendDone(); + + handles.push_back(NEWHANDLE); +} + +SP CForeignToplevelWlrManager::handleForWindow(CWindow* pWindow) { + std::erase_if(handles, [](const auto& wp) { return !wp.lock(); }); + const auto IT = std::find_if(handles.begin(), handles.end(), [pWindow](const auto& h) { return h.lock()->window() == pWindow; }); + return IT == handles.end() ? SP{} : IT->lock(); +} + +void CForeignToplevelWlrManager::onTitle(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + H->resource->sendTitle(pWindow->m_szTitle.c_str()); +} + +void CForeignToplevelWlrManager::onClass(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + H->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str()); +} + +void CForeignToplevelWlrManager::onUnmap(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H) + return; + + H->resource->sendClosed(); + H->closed = true; +} + +void CForeignToplevelWlrManager::onMoveMonitor(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + + if (!PMONITOR) + return; + + H->sendMonitor(PMONITOR); +} + +void CForeignToplevelWlrManager::onFullscreen(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + H->sendState(); +} + +void CForeignToplevelWlrManager::onNewFocus(CWindow* pWindow) { + if (finished) + return; + + if (const auto HOLD = handleForWindow(lastFocus); HOLD) + HOLD->sendState(); + + lastFocus = pWindow; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + H->sendState(); +} + +bool CForeignToplevelWlrManager::good() { + return resource->resource(); +} + +CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + static auto P = g_pHookSystem->hookDynamic("openWindow", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast(data); + for (auto& m : m_vManagers) { + m->onMap(PWINDOW); + } + }); + + static auto P1 = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast(data); + for (auto& m : m_vManagers) { + m->onUnmap(PWINDOW); + } + }); + + static auto P2 = g_pHookSystem->hookDynamic("windowTitle", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast(data); + for (auto& m : m_vManagers) { + m->onTitle(PWINDOW); + } + }); + + static auto P3 = g_pHookSystem->hookDynamic("activeWindow", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast(data); + for (auto& m : m_vManagers) { + m->onNewFocus(PWINDOW); + } + }); + + static auto P4 = g_pHookSystem->hookDynamic("moveWindow", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast(data); + for (auto& m : m_vManagers) { + m->onMoveMonitor(PWINDOW); + } + }); + + static auto P5 = g_pHookSystem->hookDynamic("fullscreen", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast(data); + for (auto& m : m_vManagers) { + m->onFullscreen(PWINDOW); + } + }); +} + +void CForeignToplevelWlrProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(std::make_shared(client, ver, id))).get(); + + if (!RESOURCE->good()) { + LOGM(ERR, "Couldn't create a foreign list"); + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CForeignToplevelWlrProtocol::onManagerResourceDestroy(CForeignToplevelWlrManager* mgr) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == mgr; }); +} + +void CForeignToplevelWlrProtocol::destroyHandle(CForeignToplevelHandleWlr* handle) { + std::erase_if(m_vHandles, [&](const auto& other) { return other.get() == handle; }); +} + +CWindow* CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res) { + for (auto& h : m_vHandles) { + if (h->res() != res) + continue; + + return h->window(); + } + + return nullptr; +} \ No newline at end of file diff --git a/src/protocols/ForeignToplevelWlr.hpp b/src/protocols/ForeignToplevelWlr.hpp new file mode 100644 index 00000000..c22a71cd --- /dev/null +++ b/src/protocols/ForeignToplevelWlr.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include "WaylandProtocol.hpp" +#include "wlr-foreign-toplevel-management-unstable-v1.hpp" + +class CWindow; +class CMonitor; + +class CForeignToplevelHandleWlr { + public: + CForeignToplevelHandleWlr(SP resource_, CWindow* pWindow); + + bool good(); + CWindow* window(); + wl_resource* res(); + + private: + SP resource; + CWindow* pWindow = nullptr; + bool closed = false; + int64_t lastMonitorID = -1; + + void sendMonitor(CMonitor* pMonitor); + void sendState(); + + friend class CForeignToplevelWlrManager; +}; + +class CForeignToplevelWlrManager { + public: + CForeignToplevelWlrManager(SP resource_); + + void onMap(CWindow* pWindow); + void onTitle(CWindow* pWindow); + void onClass(CWindow* pWindow); + void onMoveMonitor(CWindow* pWindow); + void onFullscreen(CWindow* pWindow); + void onNewFocus(CWindow* pWindow); + void onUnmap(CWindow* pWindow); + + bool good(); + + private: + SP resource; + bool finished = false; + CWindow* lastFocus = nullptr; // READ-ONLY + + SP handleForWindow(CWindow* pWindow); + + std::vector> handles; +}; + +class CForeignToplevelWlrProtocol : public IWaylandProtocol { + public: + CForeignToplevelWlrProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + CWindow* windowFromHandleResource(wl_resource* res); + + private: + void onManagerResourceDestroy(CForeignToplevelWlrManager* mgr); + void destroyHandle(CForeignToplevelHandleWlr* handle); + + // + std::vector> m_vManagers; + std::vector> m_vHandles; + + friend class CForeignToplevelWlrManager; + friend class CForeignToplevelHandleWlr; +}; + +namespace PROTO { + inline UP foreignToplevelWlr; +}; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index e2006afb..166ba1af 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -1,5 +1,6 @@ #include "ToplevelExport.hpp" #include "../Compositor.hpp" +#include "ForeignToplevelWlr.hpp" #include @@ -39,17 +40,12 @@ CToplevelExportProtocolManager::CToplevelExportProtocolManager() { Debug::log(LOG, "ToplevelExportManager started successfully!"); } -wlr_foreign_toplevel_handle_v1* zwlrHandleFromResource(wl_resource* resource) { - // we can't assert here, but it doesnt matter. - return (wlr_foreign_toplevel_handle_v1*)wl_resource_get_user_data(resource); -} - static void handleCaptureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) { g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromHandle(handle)); } static void handleCaptureToplevelWithWlr(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* handle) { - g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromZWLRHandle(handle)); + g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, PROTO::foreignToplevelWlr->windowFromHandleResource(handle)); } static void handleDestroy(wl_client* client, wl_resource* resource) { diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 50b967ed..199a26dd 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -1,7 +1,6 @@ #pragma once #include "../defines.hpp" -#include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" #include "hyprland-toplevel-export-v1-protocol.h" #include "Screencopy.hpp"